From df4b8c2a2df765bac25f5084c13d7b59997cba10 Mon Sep 17 00:00:00 2001 From: Andrew Thompson Date: Mon, 9 Mar 2009 17:09:46 +0000 Subject: libusb20 is now installed as libusb, remove the version number from the directory name. --- lib/libusb/Makefile | 25 + lib/libusb/libusb20.3 | 801 ++++++++++++++++++++++++++ lib/libusb/libusb20.c | 1141 ++++++++++++++++++++++++++++++++++++++ lib/libusb/libusb20.h | 298 ++++++++++ lib/libusb/libusb20_compat01.c | 948 +++++++++++++++++++++++++++++++ lib/libusb/libusb20_compat10.c | 29 + lib/libusb/libusb20_compat10.h | 25 + lib/libusb/libusb20_desc.c | 785 ++++++++++++++++++++++++++ lib/libusb/libusb20_desc.h | 534 ++++++++++++++++++ lib/libusb/libusb20_int.h | 228 ++++++++ lib/libusb/libusb20_ugen20.c | 1011 +++++++++++++++++++++++++++++++++ lib/libusb/usb.h | 310 +++++++++++ lib/libusb20/Makefile | 25 - lib/libusb20/libusb20.3 | 801 -------------------------- lib/libusb20/libusb20.c | 1141 -------------------------------------- lib/libusb20/libusb20.h | 298 ---------- lib/libusb20/libusb20_compat01.c | 948 ------------------------------- lib/libusb20/libusb20_compat10.c | 29 - lib/libusb20/libusb20_compat10.h | 25 - lib/libusb20/libusb20_desc.c | 785 -------------------------- lib/libusb20/libusb20_desc.h | 534 ------------------ lib/libusb20/libusb20_int.h | 228 -------- lib/libusb20/libusb20_ugen20.c | 1011 --------------------------------- lib/libusb20/usb.h | 310 ----------- 24 files changed, 6135 insertions(+), 6135 deletions(-) create mode 100644 lib/libusb/Makefile create mode 100644 lib/libusb/libusb20.3 create mode 100644 lib/libusb/libusb20.c create mode 100644 lib/libusb/libusb20.h create mode 100644 lib/libusb/libusb20_compat01.c create mode 100644 lib/libusb/libusb20_compat10.c create mode 100644 lib/libusb/libusb20_compat10.h create mode 100644 lib/libusb/libusb20_desc.c create mode 100644 lib/libusb/libusb20_desc.h create mode 100644 lib/libusb/libusb20_int.h create mode 100644 lib/libusb/libusb20_ugen20.c create mode 100644 lib/libusb/usb.h delete mode 100644 lib/libusb20/Makefile delete mode 100644 lib/libusb20/libusb20.3 delete mode 100644 lib/libusb20/libusb20.c delete mode 100644 lib/libusb20/libusb20.h delete mode 100644 lib/libusb20/libusb20_compat01.c delete mode 100644 lib/libusb20/libusb20_compat10.c delete mode 100644 lib/libusb20/libusb20_compat10.h delete mode 100644 lib/libusb20/libusb20_desc.c delete mode 100644 lib/libusb20/libusb20_desc.h delete mode 100644 lib/libusb20/libusb20_int.h delete mode 100644 lib/libusb20/libusb20_ugen20.c delete mode 100644 lib/libusb20/usb.h 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 + 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: " +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: " +. +.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 +#include +#include +#include +#include +#include + +#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 +#include +#include + +#include +#include +#include + +#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 + +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "libusb20.h" +#include "libusb20_desc.h" +#include "libusb20_int.h" + +#include +#include +#include +#include +#include + +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 +#include +#include +#include + +/* 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_ */ diff --git a/lib/libusb20/Makefile b/lib/libusb20/Makefile deleted file mode 100644 index 3eb437886022..000000000000 --- a/lib/libusb20/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# -# $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 - diff --git a/lib/libusb20/libusb20.3 b/lib/libusb20/libusb20.3 deleted file mode 100644 index bbf98fdd6ac4..000000000000 --- a/lib/libusb20/libusb20.3 +++ /dev/null @@ -1,801 +0,0 @@ -.\" -.\" 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: " -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: " -. -.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/libusb20/libusb20.c b/lib/libusb20/libusb20.c deleted file mode 100644 index 704480ab1ba7..000000000000 --- a/lib/libusb20/libusb20.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* $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 -#include -#include -#include -#include -#include - -#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/libusb20/libusb20.h b/lib/libusb20/libusb20.h deleted file mode 100644 index 89cb75eaa999..000000000000 --- a/lib/libusb20/libusb20.h +++ /dev/null @@ -1,298 +0,0 @@ -/* $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 -#include -#include - -#include -#include -#include - -#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/libusb20/libusb20_compat01.c b/lib/libusb20/libusb20_compat01.c deleted file mode 100644 index 5e1e8e181f88..000000000000 --- a/lib/libusb20/libusb20_compat01.c +++ /dev/null @@ -1,948 +0,0 @@ -/* $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 - -#include -#include -#include - -#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/libusb20/libusb20_compat10.c b/lib/libusb20/libusb20_compat10.c deleted file mode 100644 index 36244850fbda..000000000000 --- a/lib/libusb20/libusb20_compat10.c +++ /dev/null @@ -1,29 +0,0 @@ -/* $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/libusb20/libusb20_compat10.h b/lib/libusb20/libusb20_compat10.h deleted file mode 100644 index d98895fa25e8..000000000000 --- a/lib/libusb20/libusb20_compat10.h +++ /dev/null @@ -1,25 +0,0 @@ -/* $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/libusb20/libusb20_desc.c b/lib/libusb20/libusb20_desc.c deleted file mode 100644 index e0d2c54b9080..000000000000 --- a/lib/libusb20/libusb20_desc.c +++ /dev/null @@ -1,785 +0,0 @@ -/* $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 -#include -#include -#include -#include - -#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/libusb20/libusb20_desc.h b/lib/libusb20/libusb20_desc.h deleted file mode 100644 index e5e7c94d30a5..000000000000 --- a/lib/libusb20/libusb20_desc.h +++ /dev/null @@ -1,534 +0,0 @@ -/* $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/libusb20/libusb20_int.h b/lib/libusb20/libusb20_int.h deleted file mode 100644 index 494aa6d7bf39..000000000000 --- a/lib/libusb20/libusb20_int.h +++ /dev/null @@ -1,228 +0,0 @@ -/* $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/libusb20/libusb20_ugen20.c b/lib/libusb20/libusb20_ugen20.c deleted file mode 100644 index 1d97db66a65d..000000000000 --- a/lib/libusb20/libusb20_ugen20.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* $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 -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "libusb20.h" -#include "libusb20_desc.h" -#include "libusb20_int.h" - -#include -#include -#include -#include -#include - -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/libusb20/usb.h b/lib/libusb20/usb.h deleted file mode 100644 index 3963a9f0355c..000000000000 --- a/lib/libusb20/usb.h +++ /dev/null @@ -1,310 +0,0 @@ -/* $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 -#include -#include -#include - -/* 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_ */ -- cgit v1.2.3