diff --git a/CMakeLists.txt b/CMakeLists.txt index b598c973e1..5d9dd964ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,9 +208,16 @@ if(NOT CMAKE_BUILD_TYPE) "Build type (Release/Debug/RelWithDebInfo/MinSizeRe)" FORCE) endif(NOT CMAKE_BUILD_TYPE) + if(CMAKE_BUILD_TYPE STREQUAL Debug) add_definitions(-D_DEBUG -ggdb) set(wxWidgets_USE_DEBUG ON CACHE BOOL "Use wxWidgets Debugging") + + option(ENABLE_GPROF "Enable gprof profiling (must be using Debug build)" OFF) + if(ENABLE_GPROF) + add_definitions(-pg) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") + endif() endif(CMAKE_BUILD_TYPE STREQUAL Debug) if(CMAKE_BUILD_TYPE STREQUAL Release) @@ -435,6 +442,16 @@ else(SDL2_FOUND) endif(SDL_FOUND) endif(SDL2_FOUND) +include(FindLibUSB OPTIONAL) +if(LIBUSB_FOUND) + message("Using shared LibUSB") + + add_definitions(-D__LIBUSB__) + include_directories(${LIBUSB_INCLUDE_DIR}) +else(LIBUSB_FOUND) + +endif(LIBUSB_FOUND) + set(SFML_FIND_VERSION TRUE) set(SFML_FIND_VERSION_MAJOR 1) set(SFML_FIND_VERSION_MINOR 5) diff --git a/CMakeTests/FindLibUSB.cmake b/CMakeTests/FindLibUSB.cmake new file mode 100644 index 0000000000..789e6f8416 --- /dev/null +++ b/CMakeTests/FindLibUSB.cmake @@ -0,0 +1,40 @@ +# - Find libusb-1.0 library +# This module defines +# LIBUSB_INCLUDE_DIR, where to find bluetooth.h +# LIBUSB_LIBRARIES, the libraries needed to use libusb-1.0. +# LIBUSB_FOUND, If false, do not try to use libusb-1.0. +# +# Copyright (c) 2009, Michal Cihar, +# +# vim: expandtab sw=4 ts=4 sts=4: + +if (NOT LIBUSB_FOUND) + pkg_check_modules (LIBUSB_PKG libusb-1.0) + + find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h + PATHS + ${LIBUSB_PKG_INCLUDE_DIRS} + /usr/include/libusb-1.0 + /usr/include + /usr/local/include/libusb-1.0 + /usr/local/include + ) + + find_library(LIBUSB_LIBRARIES NAMES usb-1.0 + PATHS + ${LIBUSB_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + + if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) + set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found") + message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}") + else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) + set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") + message(STATUS "libusb-1.0 not found.") + endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) + + mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) +endif (NOT LIBUSB_FOUND) + diff --git a/Externals/libusb/include/libusb.h b/Externals/libusb/include/libusb.h new file mode 100644 index 0000000000..58b406f247 --- /dev/null +++ b/Externals/libusb/include/libusb.h @@ -0,0 +1,1443 @@ +/* + * Public libusb header file + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (c) 2001 Johannes Erdfelt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSB_H +#define LIBUSB_H + +#ifdef _MSC_VER +/* on MS environments, the inline keyword is available in C++ only */ +#define inline __inline +/* ssize_t is also not available (copy/paste from MinGW) */ +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#undef ssize_t +#ifdef _WIN64 + typedef __int64 ssize_t; +#else + typedef int ssize_t; +#endif /* _WIN64 */ +#endif /* _SSIZE_T_DEFINED */ +#endif /* _MSC_VER */ + +/* stdint.h is also not usually available on MS */ +#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H)) +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +#else +#include +#endif + +#include +#include +#include + +#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) +#include +#endif + +/* 'interface' might be defined as a macro on Windows, so we need to + * undefine it so as not to break the current libusb API, because + * libusb_config_descriptor has an 'interface' member + * As this can be problematic if you include windows.h after libusb.h + * in your sources, we force windows.h to be included first. */ +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#if defined(interface) +#undef interface +#endif +#endif + +/** \def LIBUSB_CALL + * \ingroup misc + * libusb's Windows calling convention. + * + * Under Windows, the selection of available compilers and configurations + * means that, unlike other platforms, there is not one true calling + * convention (calling convention: the manner in which parameters are + * passed to funcions in the generated assembly code). + * + * Matching the Windows API itself, libusb uses the WINAPI convention (which + * translates to the stdcall convention) and guarantees that the + * library is compiled in this way. The public header file also includes + * appropriate annotations so that your own software will use the right + * convention, even if another convention is being used by default within + * your codebase. + * + * The one consideration that you must apply in your software is to mark + * all functions which you use as libusb callbacks with this LIBUSB_CALL + * annotation, so that they too get compiled for the correct calling + * convention. + * + * On non-Windows operating systems, this macro is defined as nothing. This + * means that you can apply it to your code without worrying about + * cross-platform compatibility. + */ +/* LIBUSB_CALL must be defined on both definition and declaration of libusb + * functions. You'd think that declaration would be enough, but cygwin will + * complain about conflicting types unless both are marked this way. + * The placement of this macro is important too; it must appear after the + * return type, before the function name. See internal documentation for + * API_EXPORTED. + */ +#if defined(_WIN32) || defined(__CYGWIN__) +#define LIBUSB_CALL WINAPI +#else +#define LIBUSB_CALL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** \def libusb_cpu_to_le16 + * \ingroup misc + * Convert a 16-bit value from host-endian to little-endian format. On + * little endian systems, this function does nothing. On big endian systems, + * the bytes are swapped. + * \param x the host-endian value to convert + * \returns the value in little-endian byte order + */ +static inline uint16_t libusb_cpu_to_le16(const uint16_t x) +{ + union { + uint8_t b8[2]; + uint16_t b16; + } _tmp; + _tmp.b8[1] = x >> 8; + _tmp.b8[0] = x & 0xff; + return _tmp.b16; +} + +/** \def libusb_le16_to_cpu + * \ingroup misc + * Convert a 16-bit value from little-endian to host-endian format. On + * little endian systems, this function does nothing. On big endian systems, + * the bytes are swapped. + * \param x the little-endian value to convert + * \returns the value in host-endian byte order + */ +#define libusb_le16_to_cpu libusb_cpu_to_le16 + +/* standard USB stuff */ + +/** \ingroup desc + * Device and/or Interface Class codes */ +enum libusb_class_code { + /** In the context of a \ref libusb_device_descriptor "device descriptor", + * this bDeviceClass value indicates that each interface specifies its + * own class information and all interfaces operate independently. + */ + LIBUSB_CLASS_PER_INTERFACE = 0, + + /** Audio class */ + LIBUSB_CLASS_AUDIO = 1, + + /** Communications class */ + LIBUSB_CLASS_COMM = 2, + + /** Human Interface Device class */ + LIBUSB_CLASS_HID = 3, + + /** Physical */ + LIBUSB_CLASS_PHYSICAL = 5, + + /** Printer class */ + LIBUSB_CLASS_PRINTER = 7, + + /** Image class */ + LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */ + LIBUSB_CLASS_IMAGE = 6, + + /** Mass storage class */ + LIBUSB_CLASS_MASS_STORAGE = 8, + + /** Hub class */ + LIBUSB_CLASS_HUB = 9, + + /** Data class */ + LIBUSB_CLASS_DATA = 10, + + /** Smart Card */ + LIBUSB_CLASS_SMART_CARD = 0x0b, + + /** Content Security */ + LIBUSB_CLASS_CONTENT_SECURITY = 0x0d, + + /** Video */ + LIBUSB_CLASS_VIDEO = 0x0e, + + /** Personal Healthcare */ + LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f, + + /** Diagnostic Device */ + LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc, + + /** Wireless class */ + LIBUSB_CLASS_WIRELESS = 0xe0, + + /** Application class */ + LIBUSB_CLASS_APPLICATION = 0xfe, + + /** Class is vendor-specific */ + LIBUSB_CLASS_VENDOR_SPEC = 0xff +}; + +/** \ingroup desc + * Descriptor types as defined by the USB specification. */ +enum libusb_descriptor_type { + /** Device descriptor. See libusb_device_descriptor. */ + LIBUSB_DT_DEVICE = 0x01, + + /** Configuration descriptor. See libusb_config_descriptor. */ + LIBUSB_DT_CONFIG = 0x02, + + /** String descriptor */ + LIBUSB_DT_STRING = 0x03, + + /** Interface descriptor. See libusb_interface_descriptor. */ + LIBUSB_DT_INTERFACE = 0x04, + + /** Endpoint descriptor. See libusb_endpoint_descriptor. */ + LIBUSB_DT_ENDPOINT = 0x05, + + /** HID descriptor */ + LIBUSB_DT_HID = 0x21, + + /** HID report descriptor */ + LIBUSB_DT_REPORT = 0x22, + + /** Physical descriptor */ + LIBUSB_DT_PHYSICAL = 0x23, + + /** Hub descriptor */ + LIBUSB_DT_HUB = 0x29, +}; + +/* Descriptor sizes per descriptor type */ +#define LIBUSB_DT_DEVICE_SIZE 18 +#define LIBUSB_DT_CONFIG_SIZE 9 +#define LIBUSB_DT_INTERFACE_SIZE 9 +#define LIBUSB_DT_ENDPOINT_SIZE 7 +#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ +#define LIBUSB_DT_HUB_NONVAR_SIZE 7 + +#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ +#define LIBUSB_ENDPOINT_DIR_MASK 0x80 + +/** \ingroup desc + * Endpoint direction. Values for bit 7 of the + * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. + */ +enum libusb_endpoint_direction { + /** In: device-to-host */ + LIBUSB_ENDPOINT_IN = 0x80, + + /** Out: host-to-device */ + LIBUSB_ENDPOINT_OUT = 0x00 +}; + +#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ + +/** \ingroup desc + * Endpoint transfer type. Values for bits 0:1 of the + * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. + */ +enum libusb_transfer_type { + /** Control endpoint */ + LIBUSB_TRANSFER_TYPE_CONTROL = 0, + + /** Isochronous endpoint */ + LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, + + /** Bulk endpoint */ + LIBUSB_TRANSFER_TYPE_BULK = 2, + + /** Interrupt endpoint */ + LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 +}; + +/** \ingroup misc + * Standard requests, as defined in table 9-3 of the USB2 specifications */ +enum libusb_standard_request { + /** Request status of the specific recipient */ + LIBUSB_REQUEST_GET_STATUS = 0x00, + + /** Clear or disable a specific feature */ + LIBUSB_REQUEST_CLEAR_FEATURE = 0x01, + + /* 0x02 is reserved */ + + /** Set or enable a specific feature */ + LIBUSB_REQUEST_SET_FEATURE = 0x03, + + /* 0x04 is reserved */ + + /** Set device address for all future accesses */ + LIBUSB_REQUEST_SET_ADDRESS = 0x05, + + /** Get the specified descriptor */ + LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06, + + /** Used to update existing descriptors or add new descriptors */ + LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07, + + /** Get the current device configuration value */ + LIBUSB_REQUEST_GET_CONFIGURATION = 0x08, + + /** Set device configuration */ + LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, + + /** Return the selected alternate setting for the specified interface */ + LIBUSB_REQUEST_GET_INTERFACE = 0x0A, + + /** Select an alternate interface for the specified interface */ + LIBUSB_REQUEST_SET_INTERFACE = 0x0B, + + /** Set then report an endpoint's synchronization frame */ + LIBUSB_REQUEST_SYNCH_FRAME = 0x0C, +}; + +/** \ingroup misc + * Request type bits of the + * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control + * transfers. */ +enum libusb_request_type { + /** Standard */ + LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5), + + /** Class */ + LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5), + + /** Vendor */ + LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5), + + /** Reserved */ + LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) +}; + +/** \ingroup misc + * Recipient bits of the + * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control + * transfers. Values 4 through 31 are reserved. */ +enum libusb_request_recipient { + /** Device */ + LIBUSB_RECIPIENT_DEVICE = 0x00, + + /** Interface */ + LIBUSB_RECIPIENT_INTERFACE = 0x01, + + /** Endpoint */ + LIBUSB_RECIPIENT_ENDPOINT = 0x02, + + /** Other */ + LIBUSB_RECIPIENT_OTHER = 0x03, +}; + +#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C + +/** \ingroup desc + * Synchronization type for isochronous endpoints. Values for bits 2:3 of the + * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in + * libusb_endpoint_descriptor. + */ +enum libusb_iso_sync_type { + /** No synchronization */ + LIBUSB_ISO_SYNC_TYPE_NONE = 0, + + /** Asynchronous */ + LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, + + /** Adaptive */ + LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, + + /** Synchronous */ + LIBUSB_ISO_SYNC_TYPE_SYNC = 3 +}; + +#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 + +/** \ingroup desc + * Usage type for isochronous endpoints. Values for bits 4:5 of the + * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in + * libusb_endpoint_descriptor. + */ +enum libusb_iso_usage_type { + /** Data endpoint */ + LIBUSB_ISO_USAGE_TYPE_DATA = 0, + + /** Feedback endpoint */ + LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, + + /** Implicit feedback Data endpoint */ + LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, +}; + +/** \ingroup desc + * A structure representing the standard USB device descriptor. This + * descriptor is documented in section 9.6.1 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_device_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this + * context. */ + uint8_t bDescriptorType; + + /** USB specification release number in binary-coded decimal. A value of + * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ + uint16_t bcdUSB; + + /** USB-IF class code for the device. See \ref libusb_class_code. */ + uint8_t bDeviceClass; + + /** USB-IF subclass code for the device, qualified by the bDeviceClass + * value */ + uint8_t bDeviceSubClass; + + /** USB-IF protocol code for the device, qualified by the bDeviceClass and + * bDeviceSubClass values */ + uint8_t bDeviceProtocol; + + /** Maximum packet size for endpoint 0 */ + uint8_t bMaxPacketSize0; + + /** USB-IF vendor ID */ + uint16_t idVendor; + + /** USB-IF product ID */ + uint16_t idProduct; + + /** Device release number in binary-coded decimal */ + uint16_t bcdDevice; + + /** Index of string descriptor describing manufacturer */ + uint8_t iManufacturer; + + /** Index of string descriptor describing product */ + uint8_t iProduct; + + /** Index of string descriptor containing device serial number */ + uint8_t iSerialNumber; + + /** Number of possible configurations */ + uint8_t bNumConfigurations; +}; + +/** \ingroup desc + * A structure representing the standard USB endpoint descriptor. This + * descriptor is documented in section 9.6.3 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_endpoint_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in + * this context. */ + uint8_t bDescriptorType; + + /** The address of the endpoint described by this descriptor. Bits 0:3 are + * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, + * see \ref libusb_endpoint_direction. + */ + uint8_t bEndpointAddress; + + /** Attributes which apply to the endpoint when it is configured using + * the bConfigurationValue. Bits 0:1 determine the transfer type and + * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for + * isochronous endpoints and correspond to \ref libusb_iso_sync_type. + * Bits 4:5 are also only used for isochronous endpoints and correspond to + * \ref libusb_iso_usage_type. Bits 6:7 are reserved. + */ + uint8_t bmAttributes; + + /** Maximum packet size this endpoint is capable of sending/receiving. */ + uint16_t wMaxPacketSize; + + /** Interval for polling endpoint for data transfers. */ + uint8_t bInterval; + + /** For audio devices only: the rate at which synchronization feedback + * is provided. */ + uint8_t bRefresh; + + /** For audio devices only: the address if the synch endpoint */ + uint8_t bSynchAddress; + + /** Extra descriptors. If libusb encounters unknown endpoint descriptors, + * it will store them here, should you wish to parse them. */ + const unsigned char *extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; +}; + +/** \ingroup desc + * A structure representing the standard USB interface descriptor. This + * descriptor is documented in section 9.6.5 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_interface_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE + * in this context. */ + uint8_t bDescriptorType; + + /** Number of this interface */ + uint8_t bInterfaceNumber; + + /** Value used to select this alternate setting for this interface */ + uint8_t bAlternateSetting; + + /** Number of endpoints used by this interface (excluding the control + * endpoint). */ + uint8_t bNumEndpoints; + + /** USB-IF class code for this interface. See \ref libusb_class_code. */ + uint8_t bInterfaceClass; + + /** USB-IF subclass code for this interface, qualified by the + * bInterfaceClass value */ + uint8_t bInterfaceSubClass; + + /** USB-IF protocol code for this interface, qualified by the + * bInterfaceClass and bInterfaceSubClass values */ + uint8_t bInterfaceProtocol; + + /** Index of string descriptor describing this interface */ + uint8_t iInterface; + + /** Array of endpoint descriptors. This length of this array is determined + * by the bNumEndpoints field. */ + const struct libusb_endpoint_descriptor *endpoint; + + /** Extra descriptors. If libusb encounters unknown interface descriptors, + * it will store them here, should you wish to parse them. */ + const unsigned char *extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; +}; + +/** \ingroup desc + * A collection of alternate settings for a particular USB interface. + */ +struct libusb_interface { + /** Array of interface descriptors. The length of this array is determined + * by the num_altsetting field. */ + const struct libusb_interface_descriptor *altsetting; + + /** The number of alternate settings that belong to this interface */ + int num_altsetting; +}; + +/** \ingroup desc + * A structure representing the standard USB configuration descriptor. This + * descriptor is documented in section 9.6.3 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_config_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG + * in this context. */ + uint8_t bDescriptorType; + + /** Total length of data returned for this configuration */ + uint16_t wTotalLength; + + /** Number of interfaces supported by this configuration */ + uint8_t bNumInterfaces; + + /** Identifier value for this configuration */ + uint8_t bConfigurationValue; + + /** Index of string descriptor describing this configuration */ + uint8_t iConfiguration; + + /** Configuration characteristics */ + uint8_t bmAttributes; + + /** Maximum power consumption of the USB device from this bus in this + * configuration when the device is fully opreation. Expressed in units + * of 2 mA. */ + uint8_t MaxPower; + + /** Array of interfaces supported by this configuration. The length of + * this array is determined by the bNumInterfaces field. */ + const struct libusb_interface *interface; + + /** Extra descriptors. If libusb encounters unknown configuration + * descriptors, it will store them here, should you wish to parse them. */ + const unsigned char *extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; +}; + +/** \ingroup asyncio + * Setup packet for control transfers. */ +struct libusb_control_setup { + /** Request type. Bits 0:4 determine recipient, see + * \ref libusb_request_recipient. Bits 5:6 determine type, see + * \ref libusb_request_type. Bit 7 determines data transfer direction, see + * \ref libusb_endpoint_direction. + */ + uint8_t bmRequestType; + + /** Request. If the type bits of bmRequestType are equal to + * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD + * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to + * \ref libusb_standard_request. For other cases, use of this field is + * application-specific. */ + uint8_t bRequest; + + /** Value. Varies according to request */ + uint16_t wValue; + + /** Index. Varies according to request, typically used to pass an index + * or offset */ + uint16_t wIndex; + + /** Number of bytes to transfer */ + uint16_t wLength; +}; + +#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup)) + +/* libusb */ + +struct libusb_context; +struct libusb_device; +struct libusb_device_handle; + +/** \ingroup lib + * Structure representing the libusb version. + */ +struct libusb_version { + /** Library major version. */ + const uint16_t major; + + /** Library minor version. */ + const uint16_t minor; + + /** Library micro version. */ + const uint16_t micro; + + /** Library nano version. This field is only nonzero on Windows. */ + const uint16_t nano; + + /** Library release candidate suffix string, e.g. "-rc4". */ + const char *rc; + + /** Output of `git describe --tags` at library build time. */ + const char *describe; +}; + +/** \ingroup lib + * Structure representing a libusb session. The concept of individual libusb + * sessions allows for your program to use two libraries (or dynamically + * load two modules) which both independently use libusb. This will prevent + * interference between the individual libusb users - for example + * libusb_set_debug() will not affect the other user of the library, and + * libusb_exit() will not destroy resources that the other user is still + * using. + * + * Sessions are created by libusb_init() and destroyed through libusb_exit(). + * If your application is guaranteed to only ever include a single libusb + * user (i.e. you), you do not have to worry about contexts: pass NULL in + * every function call where a context is required. The default context + * will be used. + * + * For more information, see \ref contexts. + */ +typedef struct libusb_context libusb_context; + +/** \ingroup dev + * Structure representing a USB device detected on the system. This is an + * opaque type for which you are only ever provided with a pointer, usually + * originating from libusb_get_device_list(). + * + * Certain operations can be performed on a device, but in order to do any + * I/O you will have to first obtain a device handle using libusb_open(). + * + * Devices are reference counted with libusb_device_ref() and + * libusb_device_unref(), and are freed when the reference count reaches 0. + * New devices presented by libusb_get_device_list() have a reference count of + * 1, and libusb_free_device_list() can optionally decrease the reference count + * on all devices in the list. libusb_open() adds another reference which is + * later destroyed by libusb_close(). + */ +typedef struct libusb_device libusb_device; + + +/** \ingroup dev + * Structure representing a handle on a USB device. This is an opaque type for + * which you are only ever provided with a pointer, usually originating from + * libusb_open(). + * + * A device handle is used to perform I/O and other operations. When finished + * with a device handle, you should call libusb_close(). + */ +typedef struct libusb_device_handle libusb_device_handle; + +/** \ingroup dev + * Speed codes. Indicates the speed at which the device is operating. + */ +enum libusb_speed { + /** The OS doesn't report or know the device speed. */ + LIBUSB_SPEED_UNKNOWN = 0, + + /** The device is operating at low speed (1.5MBit/s). */ + LIBUSB_SPEED_LOW = 1, + + /** The device is operating at full speed (12MBit/s). */ + LIBUSB_SPEED_FULL = 2, + + /** The device is operating at high speed (480MBit/s). */ + LIBUSB_SPEED_HIGH = 3, + + /** The device is operating at super speed (5000MBit/s). */ + LIBUSB_SPEED_SUPER = 4, +}; + +/** \ingroup misc + * Error codes. Most libusb functions return 0 on success or one of these + * codes on failure. + * You can call \ref libusb_error_name() to retrieve a string representation + * of an error code. + */ +enum libusb_error { + /** Success (no error) */ + LIBUSB_SUCCESS = 0, + + /** Input/output error */ + LIBUSB_ERROR_IO = -1, + + /** Invalid parameter */ + LIBUSB_ERROR_INVALID_PARAM = -2, + + /** Access denied (insufficient permissions) */ + LIBUSB_ERROR_ACCESS = -3, + + /** No such device (it may have been disconnected) */ + LIBUSB_ERROR_NO_DEVICE = -4, + + /** Entity not found */ + LIBUSB_ERROR_NOT_FOUND = -5, + + /** Resource busy */ + LIBUSB_ERROR_BUSY = -6, + + /** Operation timed out */ + LIBUSB_ERROR_TIMEOUT = -7, + + /** Overflow */ + LIBUSB_ERROR_OVERFLOW = -8, + + /** Pipe error */ + LIBUSB_ERROR_PIPE = -9, + + /** System call interrupted (perhaps due to signal) */ + LIBUSB_ERROR_INTERRUPTED = -10, + + /** Insufficient memory */ + LIBUSB_ERROR_NO_MEM = -11, + + /** Operation not supported or unimplemented on this platform */ + LIBUSB_ERROR_NOT_SUPPORTED = -12, + + /* NB! Remember to update libusb_error_name() + when adding new error codes here. */ + + /** Other error */ + LIBUSB_ERROR_OTHER = -99, +}; + +/** \ingroup asyncio + * Transfer status codes */ +enum libusb_transfer_status { + /** Transfer completed without error. Note that this does not indicate + * that the entire amount of requested data was transferred. */ + LIBUSB_TRANSFER_COMPLETED, + + /** Transfer failed */ + LIBUSB_TRANSFER_ERROR, + + /** Transfer timed out */ + LIBUSB_TRANSFER_TIMED_OUT, + + /** Transfer was cancelled */ + LIBUSB_TRANSFER_CANCELLED, + + /** For bulk/interrupt endpoints: halt condition detected (endpoint + * stalled). For control endpoints: control request not supported. */ + LIBUSB_TRANSFER_STALL, + + /** Device was disconnected */ + LIBUSB_TRANSFER_NO_DEVICE, + + /** Device sent more data than requested */ + LIBUSB_TRANSFER_OVERFLOW, +}; + +/** \ingroup asyncio + * libusb_transfer.flags values */ +enum libusb_transfer_flags { + /** Report short frames as errors */ + LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0, + + /** Automatically free() transfer buffer during libusb_free_transfer() */ + LIBUSB_TRANSFER_FREE_BUFFER = 1<<1, + + /** Automatically call libusb_free_transfer() after callback returns. + * If this flag is set, it is illegal to call libusb_free_transfer() + * from your transfer callback, as this will result in a double-free + * when this flag is acted upon. */ + LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2, + + /** Terminate transfers that are a multiple of the endpoint's + * wMaxPacketSize with an extra zero length packet. This is useful + * when a device protocol mandates that each logical request is + * terminated by an incomplete packet (i.e. the logical requests are + * not separated by other means). + * + * This flag only affects host-to-device transfers to bulk and interrupt + * endpoints. In other situations, it is ignored. + * + * This flag only affects transfers with a length that is a multiple of + * the endpoint's wMaxPacketSize. On transfers of other lengths, this + * flag has no effect. Therefore, if you are working with a device that + * needs a ZLP whenever the end of the logical request falls on a packet + * boundary, then it is sensible to set this flag on every + * transfer (you do not have to worry about only setting it on transfers + * that end on the boundary). + * + * This flag is currently only supported on Linux. + * On other systems, libusb_submit_transfer() will return + * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set. + * + * Available since libusb-1.0.9. + */ + LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3, +}; + +/** \ingroup asyncio + * Isochronous packet descriptor. */ +struct libusb_iso_packet_descriptor { + /** Length of data to request in this packet */ + unsigned int length; + + /** Amount of data that was actually transferred */ + unsigned int actual_length; + + /** Status code for this packet */ + enum libusb_transfer_status status; +}; + +struct libusb_transfer; + +/** \ingroup asyncio + * Asynchronous transfer callback function type. When submitting asynchronous + * transfers, you pass a pointer to a callback function of this type via the + * \ref libusb_transfer::callback "callback" member of the libusb_transfer + * structure. libusb will call this function later, when the transfer has + * completed or failed. See \ref asyncio for more information. + * \param transfer The libusb_transfer struct the callback function is being + * notified about. + */ +typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer); + +/** \ingroup asyncio + * The generic USB transfer structure. The user populates this structure and + * then submits it in order to request a transfer. After the transfer has + * completed, the library populates the transfer with the results and passes + * it back to the user. + */ +struct libusb_transfer { + /** Handle of the device that this transfer will be submitted to */ + libusb_device_handle *dev_handle; + + /** A bitwise OR combination of \ref libusb_transfer_flags. */ + uint8_t flags; + + /** Address of the endpoint where this transfer will be sent. */ + unsigned char endpoint; + + /** Type of the endpoint from \ref libusb_transfer_type */ + unsigned char type; + + /** Timeout for this transfer in millseconds. A value of 0 indicates no + * timeout. */ + unsigned int timeout; + + /** The status of the transfer. Read-only, and only for use within + * transfer callback function. + * + * If this is an isochronous transfer, this field may read COMPLETED even + * if there were errors in the frames. Use the + * \ref libusb_iso_packet_descriptor::status "status" field in each packet + * to determine if errors occurred. */ + enum libusb_transfer_status status; + + /** Length of the data buffer */ + int length; + + /** Actual length of data that was transferred. Read-only, and only for + * use within transfer callback function. Not valid for isochronous + * endpoint transfers. */ + int actual_length; + + /** Callback function. This will be invoked when the transfer completes, + * fails, or is cancelled. */ + libusb_transfer_cb_fn callback; + + /** User context data to pass to the callback function. */ + void *user_data; + + /** Data buffer */ + unsigned char *buffer; + + /** Number of isochronous packets. Only used for I/O with isochronous + * endpoints. */ + int num_iso_packets; + + /** Isochronous packet descriptors, for isochronous transfers only. */ + struct libusb_iso_packet_descriptor iso_packet_desc +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + [] /* valid C99 code */ +#else + [0] /* non-standard, but usually working code */ +#endif + ; +}; + +/** \ingroup misc + * Capabilities supported by this instance of libusb. Test if the loaded + * library supports a given capability by calling + * \ref libusb_has_capability(). + */ +enum libusb_capability { + /** The libusb_has_capability() API is available. */ + LIBUSB_CAP_HAS_CAPABILITY = 0, +}; + +int LIBUSB_CALL libusb_init(libusb_context **ctx); +void LIBUSB_CALL libusb_exit(libusb_context *ctx); +void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); +const struct libusb_version * LIBUSB_CALL libusb_get_version(void); +int LIBUSB_CALL libusb_has_capability(uint32_t capability); +const char * LIBUSB_CALL libusb_error_name(int errcode); + +ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, + libusb_device ***list); +void LIBUSB_CALL libusb_free_device_list(libusb_device **list, + int unref_devices); +libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev); +void LIBUSB_CALL libusb_unref_device(libusb_device *dev); + +int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev, + int *config); +int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev, + struct libusb_device_descriptor *desc); +int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev, + struct libusb_config_descriptor **config); +int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev, + uint8_t config_index, struct libusb_config_descriptor **config); +int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev, + uint8_t bConfigurationValue, struct libusb_config_descriptor **config); +void LIBUSB_CALL libusb_free_config_descriptor( + struct libusb_config_descriptor *config); +uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev); +uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev); +int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev); +int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, + unsigned char endpoint); +int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, + unsigned char endpoint); + +int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); +void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); +libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); + +int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev, + int configuration); +int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev, + int interface_number); +int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev, + int interface_number); + +libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( + libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); + +int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev, + int interface_number, int alternate_setting); +int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev, + unsigned char endpoint); +int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev); + +int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev, + int interface_number); +int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev, + int interface_number); +int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev, + int interface_number); + +/* async I/O */ + +/** \ingroup asyncio + * Get the data section of a control transfer. This convenience function is here + * to remind you that the data does not start until 8 bytes into the actual + * buffer, as the setup packet comes first. + * + * Calling this function only makes sense from a transfer callback function, + * or situations where you have already allocated a suitably sized buffer at + * transfer->buffer. + * + * \param transfer a transfer + * \returns pointer to the first byte of the data section + */ +static inline unsigned char *libusb_control_transfer_get_data( + struct libusb_transfer *transfer) +{ + return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; +} + +/** \ingroup asyncio + * Get the control setup packet of a control transfer. This convenience + * function is here to remind you that the control setup occupies the first + * 8 bytes of the transfer data buffer. + * + * Calling this function only makes sense from a transfer callback function, + * or situations where you have already allocated a suitably sized buffer at + * transfer->buffer. + * + * \param transfer a transfer + * \returns a casted pointer to the start of the transfer data buffer + */ +static inline struct libusb_control_setup *libusb_control_transfer_get_setup( + struct libusb_transfer *transfer) +{ + return (struct libusb_control_setup *) transfer->buffer; +} + +/** \ingroup asyncio + * Helper function to populate the setup packet (first 8 bytes of the data + * buffer) for a control transfer. The wIndex, wValue and wLength values should + * be given in host-endian byte order. + * + * \param buffer buffer to output the setup packet into + * \param bmRequestType see the + * \ref libusb_control_setup::bmRequestType "bmRequestType" field of + * \ref libusb_control_setup + * \param bRequest see the + * \ref libusb_control_setup::bRequest "bRequest" field of + * \ref libusb_control_setup + * \param wValue see the + * \ref libusb_control_setup::wValue "wValue" field of + * \ref libusb_control_setup + * \param wIndex see the + * \ref libusb_control_setup::wIndex "wIndex" field of + * \ref libusb_control_setup + * \param wLength see the + * \ref libusb_control_setup::wLength "wLength" field of + * \ref libusb_control_setup + */ +static inline void libusb_fill_control_setup(unsigned char *buffer, + uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + uint16_t wLength) +{ + struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; + setup->bmRequestType = bmRequestType; + setup->bRequest = bRequest; + setup->wValue = libusb_cpu_to_le16(wValue); + setup->wIndex = libusb_cpu_to_le16(wIndex); + setup->wLength = libusb_cpu_to_le16(wLength); +} + +struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets); +int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer); +int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer); +void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields + * for a control transfer. + * + * If you pass a transfer buffer to this function, the first 8 bytes will + * be interpreted as a control setup packet, and the wLength field will be + * used to automatically populate the \ref libusb_transfer::length "length" + * field of the transfer. Therefore the recommended approach is: + * -# Allocate a suitably sized data buffer (including space for control setup) + * -# Call libusb_fill_control_setup() + * -# If this is a host-to-device transfer with a data stage, put the data + * in place after the setup packet + * -# Call this function + * -# Call libusb_submit_transfer() + * + * It is also legal to pass a NULL buffer to this function, in which case this + * function will not attempt to populate the length field. Remember that you + * must then populate the buffer and length fields later. + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param buffer data buffer. If provided, this function will interpret the + * first 8 bytes as a setup packet and infer the transfer length from that. + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_control_transfer( + struct libusb_transfer *transfer, libusb_device_handle *dev_handle, + unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data, + unsigned int timeout) +{ + struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; + transfer->dev_handle = dev_handle; + transfer->endpoint = 0; + transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; + transfer->timeout = timeout; + transfer->buffer = buffer; + if (setup) + transfer->length = LIBUSB_CONTROL_SETUP_SIZE + + libusb_le16_to_cpu(setup->wLength); + transfer->user_data = user_data; + transfer->callback = callback; +} + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields + * for a bulk transfer. + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param endpoint address of the endpoint where this transfer will be sent + * \param buffer data buffer + * \param length length of data buffer + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, + libusb_device_handle *dev_handle, unsigned char endpoint, + unsigned char *buffer, int length, libusb_transfer_cb_fn callback, + void *user_data, unsigned int timeout) +{ + transfer->dev_handle = dev_handle; + transfer->endpoint = endpoint; + transfer->type = LIBUSB_TRANSFER_TYPE_BULK; + transfer->timeout = timeout; + transfer->buffer = buffer; + transfer->length = length; + transfer->user_data = user_data; + transfer->callback = callback; +} + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields + * for an interrupt transfer. + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param endpoint address of the endpoint where this transfer will be sent + * \param buffer data buffer + * \param length length of data buffer + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_interrupt_transfer( + struct libusb_transfer *transfer, libusb_device_handle *dev_handle, + unsigned char endpoint, unsigned char *buffer, int length, + libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) +{ + transfer->dev_handle = dev_handle; + transfer->endpoint = endpoint; + transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; + transfer->timeout = timeout; + transfer->buffer = buffer; + transfer->length = length; + transfer->user_data = user_data; + transfer->callback = callback; +} + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields + * for an isochronous transfer. + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param endpoint address of the endpoint where this transfer will be sent + * \param buffer data buffer + * \param length length of data buffer + * \param num_iso_packets the number of isochronous packets + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, + libusb_device_handle *dev_handle, unsigned char endpoint, + unsigned char *buffer, int length, int num_iso_packets, + libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) +{ + transfer->dev_handle = dev_handle; + transfer->endpoint = endpoint; + transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; + transfer->timeout = timeout; + transfer->buffer = buffer; + transfer->length = length; + transfer->num_iso_packets = num_iso_packets; + transfer->user_data = user_data; + transfer->callback = callback; +} + +/** \ingroup asyncio + * Convenience function to set the length of all packets in an isochronous + * transfer, based on the num_iso_packets field in the transfer structure. + * + * \param transfer a transfer + * \param length the length to set in each isochronous packet descriptor + * \see libusb_get_max_packet_size() + */ +static inline void libusb_set_iso_packet_lengths( + struct libusb_transfer *transfer, unsigned int length) +{ + int i; + for (i = 0; i < transfer->num_iso_packets; i++) + transfer->iso_packet_desc[i].length = length; +} + +/** \ingroup asyncio + * Convenience function to locate the position of an isochronous packet + * within the buffer of an isochronous transfer. + * + * This is a thorough function which loops through all preceding packets, + * accumulating their lengths to find the position of the specified packet. + * Typically you will assign equal lengths to each packet in the transfer, + * and hence the above method is sub-optimal. You may wish to use + * libusb_get_iso_packet_buffer_simple() instead. + * + * \param transfer a transfer + * \param packet the packet to return the address of + * \returns the base address of the packet buffer inside the transfer buffer, + * or NULL if the packet does not exist. + * \see libusb_get_iso_packet_buffer_simple() + */ +static inline unsigned char *libusb_get_iso_packet_buffer( + struct libusb_transfer *transfer, unsigned int packet) +{ + int i; + size_t offset = 0; + int _packet; + + /* oops..slight bug in the API. packet is an unsigned int, but we use + * signed integers almost everywhere else. range-check and convert to + * signed to avoid compiler warnings. FIXME for libusb-2. */ + if (packet > INT_MAX) + return NULL; + _packet = packet; + + if (_packet >= transfer->num_iso_packets) + return NULL; + + for (i = 0; i < _packet; i++) + offset += transfer->iso_packet_desc[i].length; + + return transfer->buffer + offset; +} + +/** \ingroup asyncio + * Convenience function to locate the position of an isochronous packet + * within the buffer of an isochronous transfer, for transfers where each + * packet is of identical size. + * + * This function relies on the assumption that every packet within the transfer + * is of identical size to the first packet. Calculating the location of + * the packet buffer is then just a simple calculation: + * buffer + (packet_size * packet) + * + * Do not use this function on transfers other than those that have identical + * packet lengths for each packet. + * + * \param transfer a transfer + * \param packet the packet to return the address of + * \returns the base address of the packet buffer inside the transfer buffer, + * or NULL if the packet does not exist. + * \see libusb_get_iso_packet_buffer() + */ +static inline unsigned char *libusb_get_iso_packet_buffer_simple( + struct libusb_transfer *transfer, unsigned int packet) +{ + int _packet; + + /* oops..slight bug in the API. packet is an unsigned int, but we use + * signed integers almost everywhere else. range-check and convert to + * signed to avoid compiler warnings. FIXME for libusb-2. */ + if (packet > INT_MAX) + return NULL; + _packet = packet; + + if (_packet >= transfer->num_iso_packets) + return NULL; + + return transfer->buffer + (transfer->iso_packet_desc[0].length * _packet); +} + +/* sync I/O */ + +int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle, + uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + unsigned char *data, uint16_t wLength, unsigned int timeout); + +int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle, + unsigned char endpoint, unsigned char *data, int length, + int *actual_length, unsigned int timeout); + +int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, + unsigned char endpoint, unsigned char *data, int length, + int *actual_length, unsigned int timeout); + +/** \ingroup desc + * Retrieve a descriptor from the default control pipe. + * This is a convenience function which formulates the appropriate control + * message to retrieve the descriptor. + * + * \param dev a device handle + * \param desc_type the descriptor type, see \ref libusb_descriptor_type + * \param desc_index the index of the descriptor to retrieve + * \param data output buffer for descriptor + * \param length size of data buffer + * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure + */ +static inline int libusb_get_descriptor(libusb_device_handle *dev, + uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length) +{ + return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, + (uint16_t) length, 1000); +} + +/** \ingroup desc + * Retrieve a descriptor from a device. + * This is a convenience function which formulates the appropriate control + * message to retrieve the descriptor. The string returned is Unicode, as + * detailed in the USB specifications. + * + * \param dev a device handle + * \param desc_index the index of the descriptor to retrieve + * \param langid the language ID for the string descriptor + * \param data output buffer for descriptor + * \param length size of data buffer + * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure + * \see libusb_get_string_descriptor_ascii() + */ +static inline int libusb_get_string_descriptor(libusb_device_handle *dev, + uint8_t desc_index, uint16_t langid, unsigned char *data, int length) +{ + return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index), + langid, data, (uint16_t) length, 1000); +} + +int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev, + uint8_t desc_index, unsigned char *data, int length); + +/* polling and timeouts */ + +int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx); +void LIBUSB_CALL libusb_lock_events(libusb_context *ctx); +void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx); +int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx); +int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx); +void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx); +void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx); +int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); + +int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx, + struct timeval *tv); +int LIBUSB_CALL libusb_handle_events_timeout_completed(libusb_context *ctx, + struct timeval *tv, int *completed); +int LIBUSB_CALL libusb_handle_events(libusb_context *ctx); +int LIBUSB_CALL libusb_handle_events_completed(libusb_context *ctx, int *completed); +int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx, + struct timeval *tv); +int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); +int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx, + struct timeval *tv); + +/** \ingroup poll + * File descriptor for polling + */ +struct libusb_pollfd { + /** Numeric file descriptor */ + int fd; + + /** Event flags to poll for from . POLLIN indicates that you + * should monitor this file descriptor for becoming ready to read from, + * and POLLOUT indicates that you should monitor this file descriptor for + * nonblocking write readiness. */ + short events; +}; + +/** \ingroup poll + * Callback function, invoked when a new file descriptor should be added + * to the set of file descriptors monitored for events. + * \param fd the new file descriptor + * \param events events to monitor for, see \ref libusb_pollfd for a + * description + * \param user_data User data pointer specified in + * libusb_set_pollfd_notifiers() call + * \see libusb_set_pollfd_notifiers() + */ +typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events, + void *user_data); + +/** \ingroup poll + * Callback function, invoked when a file descriptor should be removed from + * the set of file descriptors being monitored for events. After returning + * from this callback, do not use that file descriptor again. + * \param fd the file descriptor to stop monitoring + * \param user_data User data pointer specified in + * libusb_set_pollfd_notifiers() call + * \see libusb_set_pollfd_notifiers() + */ +typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data); + +const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( + libusb_context *ctx); +void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, + libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, + void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Externals/libusb/win32/libusb-1.0.lib b/Externals/libusb/win32/libusb-1.0.lib new file mode 100644 index 0000000000..0434d5ebde Binary files /dev/null and b/Externals/libusb/win32/libusb-1.0.lib differ diff --git a/Externals/libusb/x64/libusb-1.0.lib b/Externals/libusb/x64/libusb-1.0.lib new file mode 100644 index 0000000000..8f67e7d1c2 Binary files /dev/null and b/Externals/libusb/x64/libusb-1.0.lib differ diff --git a/Source/Core/Common/Src/Log.h b/Source/Core/Common/Src/Log.h index 766887d5aa..df208b31db 100644 --- a/Source/Core/Common/Src/Log.h +++ b/Source/Core/Common/Src/Log.h @@ -65,6 +65,7 @@ enum LOG_TYPE { WII_IPC_DVD, WII_IPC_ES, WII_IPC_FILEIO, + WII_IPC_HID, WII_IPC_HLE, WII_IPC_NET, WII_IPC_WC24, @@ -100,10 +101,10 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, ; #if defined LOGGING || defined _DEBUG || defined DEBUGFAST -#define MAX_LOGLEVEL DEBUG_LEVEL +#define MAX_LOGLEVEL WARNING_LEVEL #else #ifndef MAX_LOGLEVEL - #define MAX_LOGLEVEL DEBUG_LEVEL +#define MAX_LOGLEVEL DEBUG_LEVEL #endif // loglevel #endif // logging diff --git a/Source/Core/Common/Src/LogManager.cpp b/Source/Core/Common/Src/LogManager.cpp index 8c73910895..26db5cbfc1 100644 --- a/Source/Core/Common/Src/LogManager.cpp +++ b/Source/Core/Common/Src/LogManager.cpp @@ -72,6 +72,7 @@ LogManager::LogManager() m_Log[LogTypes::WIIMOTE] = new LogContainer("Wiimote", "Wiimote"); m_Log[LogTypes::WII_IOB] = new LogContainer("WII_IOB", "WII IO Bridge"); m_Log[LogTypes::WII_IPC] = new LogContainer("WII_IPC", "WII IPC"); + m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE"); m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD"); m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 2b16579ac5..ca304c18af 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -70,8 +70,8 @@ set(SRCS Src/ActionReplay.cpp Src/HW/CPU.cpp Src/HW/DSP.cpp Src/HW/DSPHLE/UCodes/UCode_AX.cpp - Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp - Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp + Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp + Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp Src/HW/DSPHLE/UCodes/UCode_CARD.cpp Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp Src/HW/DSPHLE/UCodes/UCode_ROM.cpp @@ -201,6 +201,13 @@ if(NOT USE_GLES) set(LIBS ${LIBS} videoogl) endif() + +if(LIBUSB_FOUND) + # Using shared LibUSB + set(LIBS ${LIBS} ${LIBUSB_LIBRARIES}) + set(SRCS ${SRCS} Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp) +endif(LIBUSB_FOUND) + if(WIN32) set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Win32.cpp Src/stdafx.cpp Src/HW/WiimoteReal/IOWin.cpp) diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index e539cfaa68..7c50276e87 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -115,7 +115,7 @@ - .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);%(AdditionalIncludeDirectories) + .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories) true @@ -127,7 +127,7 @@ - .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);%(AdditionalIncludeDirectories) + .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories) true @@ -139,7 +139,7 @@ - .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);%(AdditionalIncludeDirectories) + .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories) true @@ -153,7 +153,7 @@ - .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);%(AdditionalIncludeDirectories) + .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories) true @@ -167,7 +167,7 @@ - .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);%(AdditionalIncludeDirectories) + .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories) true @@ -181,7 +181,7 @@ - .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);%(AdditionalIncludeDirectories) + .\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\openssl;..\..\..\Externals\openssl\$(PlatformName);..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories) true @@ -328,6 +328,7 @@ + @@ -538,6 +539,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index c315f46904..ad7ff5a17d 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -566,7 +566,10 @@ HW %28Flipper/Hollywood%29\GCMemcard - IPC HLE %28IOS/Starlet%29\Net + IPC HLE %28IOS/Starlet%29\Net + + + IPC HLE %28IOS/Starlet%29\USB @@ -1063,6 +1066,9 @@ IPC HLE %28IOS/Starlet%29\Net + + IPC HLE %28IOS/Starlet%29\USB + @@ -1203,5 +1209,8 @@ {3e9e6e83-c1bf-45f9-aeff-231f98f60d29} + + {321a9af5-9b3d-4620-888c-fe9d02e9559e} + diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp index e85797b8f8..076404ce18 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -52,6 +52,10 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC #include "WII_IPC_HLE_Device_usb_kbd.h" #include "WII_IPC_HLE_Device_sdio_slot0.h" +#if defined(__LIBUSB__) || defined (_WIN32) + #include "WII_IPC_HLE_Device_hid.h" +#endif + #include "FileUtil.h" // For Copy #include "../ConfigManager.h" #include "../HW/CPU.h" @@ -80,6 +84,7 @@ IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT]; typedef std::deque ipc_msg_queue; static ipc_msg_queue request_queue; // ppc -> arm static ipc_msg_queue reply_queue; // arm -> ppc +static std::mutex s_reply_queue; void Init() { @@ -116,7 +121,11 @@ void Init() g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, std::string("/dev/usb/kbd")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, std::string("/dev/sdio/slot0")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/sdio/slot1")); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++; + #if defined(__LIBUSB__) || defined(_WIN32) + g_DeviceMap[i] = new CWII_IPC_HLE_Device_hid(i, std::string("/dev/usb/hid")); i++; + #else + g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++; + #endif g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/oh1")); i++; g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); i++; } @@ -154,7 +163,12 @@ void Reset(bool _bHard) g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end()); } request_queue.clear(); - reply_queue.clear(); + + // lock due to using reply_queue + { + std::lock_guard lk(s_reply_queue); + reply_queue.clear(); + } } void Shutdown() @@ -236,6 +250,8 @@ IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName void DoState(PointerWrap &p) { + std::lock_guard lk(s_reply_queue); + p.Do(request_queue); p.Do(reply_queue); @@ -531,6 +547,7 @@ void EnqRequest(u32 _Address) // Called when IOS module has some reply void EnqReply(u32 _Address) { + std::lock_guard lk(s_reply_queue); reply_queue.push_back(_Address); } @@ -555,12 +572,16 @@ void Update() Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG); #endif } - - if (reply_queue.size()) + + // lock due to using reply_queue { - WII_IPCInterface::GenerateReply(reply_queue.front()); - INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front()); - reply_queue.pop_front(); + std::lock_guard lk(s_reply_queue); + if (reply_queue.size()) + { + WII_IPCInterface::GenerateReply(reply_queue.front()); + INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front()); + reply_queue.pop_front(); + } } } diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp new file mode 100644 index 0000000000..2996cdf563 --- /dev/null +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp @@ -0,0 +1,612 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "../Core.h" +#include "../Debugger/Debugger_SymbolMap.h" +#include "../HW/WII_IPC.h" +#include "WII_IPC_HLE.h" +#include "WII_IPC_HLE_Device_hid.h" +#include "errno.h" + +#if defined(_MSC_VER) || defined(__MINGW32__) +# include +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED +struct timeval { + long tv_sec; + long tv_usec; +}; +#endif /* _TIMEVAL_DEFINED */ +#else +# include +#endif + +#define MAX_DEVICE_DEVNUM 256 +static u64 hidDeviceAliases[MAX_DEVICE_DEVNUM]; + +// Regular thread +void CWII_IPC_HLE_Device_hid::checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid) +{ + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500; + while (hid->usb_thread_running) + { + + static u16 timeToFill = 0; + if (timeToFill == 0) + { + if (hid->deviceCommandAddress != 0){ + hid->FillOutDevices(Memory::Read_U32(hid->deviceCommandAddress + 0x18), Memory::Read_U32(hid->deviceCommandAddress + 0x1C)); + + Memory::Write_U32(8, hid->deviceCommandAddress); + // IOS seems to write back the command that was responded to + Memory::Write_U32(/*COMMAND_IOCTL*/ 6, hid->deviceCommandAddress + 8); + + // Return value + Memory::Write_U32(0, hid->deviceCommandAddress + 4); + + WII_IPC_HLE_Interface::EnqReply(hid->deviceCommandAddress); + hid->deviceCommandAddress = 0; + } + } + timeToFill+=8; + libusb_handle_events_timeout(NULL, &tv); + } + + return; +} + +void CWII_IPC_HLE_Device_hid::handleUsbUpdates(struct libusb_transfer *transfer) +{ + int ret = HIDERR_NO_DEVICE_FOUND; + u32 replyAddress = (u32)(size_t)transfer->user_data; + if (transfer->status == LIBUSB_TRANSFER_COMPLETED) + { + ret = transfer->length; + } + + Memory::Write_U32(8, replyAddress); + // IOS seems to write back the command that was responded to + Memory::Write_U32(/*COMMAND_IOCTL*/ 6, replyAddress + 8); + + // Return value + Memory::Write_U32(ret, replyAddress + 4); + + WII_IPC_HLE_Interface::EnqReply(replyAddress); + //DEBUG_LOG(WII_IPC_HID, "OMG OMG OMG I GOT A CALLBACK, IMMA BE FAMOUS %d %d %d", transfer->actual_length, transfer->length, transfer->status); +} + + +CWII_IPC_HLE_Device_hid::CWII_IPC_HLE_Device_hid(u32 _DeviceID, const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) +{ + deviceCommandAddress = 0; + memset(hidDeviceAliases, 0, sizeof(hidDeviceAliases)); + libusb_init(NULL); + + usb_thread_running = true; + usb_thread = std::thread(checkUsbUpdates, this); +} + +CWII_IPC_HLE_Device_hid::~CWII_IPC_HLE_Device_hid() +{ + usb_thread_running = false; + usb_thread.join(); + + for ( std::map::const_iterator iter = open_devices.begin(); iter != open_devices.end(); ++iter ) + { + libusb_close(iter->second); + } + open_devices.clear(); + + + libusb_exit(NULL); +} + +bool CWII_IPC_HLE_Device_hid::Open(u32 _CommandAddress, u32 _Mode) +{ + DEBUG_LOG(WII_IPC_HID, "HID::Open"); + m_Active = true; + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + return true; +} + +bool CWII_IPC_HLE_Device_hid::Close(u32 _CommandAddress, bool _bForce) +{ + DEBUG_LOG(WII_IPC_HID, "HID::Close"); + m_Active = false; + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + return true; +} + +u32 CWII_IPC_HLE_Device_hid::Update() +{ + + u32 work_done = 0; + return work_done; +} + +bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) +{ + u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + + u32 ReturnValue = 0; + switch (Parameter) + { + case IOCTL_HID_GET_ATTACHED: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Get Attached) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + deviceCommandAddress = _CommandAddress; + return false; + break; + } + case IOCTL_HID_OPEN: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Open) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + + //hid version, apparently + ReturnValue = 0x40001; + break; + } + case IOCTL_HID_SET_SUSPEND: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Set Suspend) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + // not actually implemented in IOS + ReturnValue = 0; + break; + } + case IOCTL_HID_CANCEL_INTERRUPT: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Cancel Interrupt) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + ReturnValue = 0; + break; + } + case IOCTL_HID_CONTROL: + { + /* + ERROR CODES: + -4 Cant find device specified + */ + + u32 dev_num = Memory::Read_U32(BufferIn+0x10); + u8 bmRequestType = Memory::Read_U8(BufferIn+0x14); + u8 bRequest = Memory::Read_U8(BufferIn+0x15); + u16 wValue = Memory::Read_U16(BufferIn+0x16); + u16 wIndex = Memory::Read_U16(BufferIn+0x18); + u16 wLength = Memory::Read_U16(BufferIn+0x1A); + u32 data = Memory::Read_U32(BufferIn+0x1C); + + ReturnValue = HIDERR_NO_DEVICE_FOUND; + + libusb_device_handle * dev_handle = GetDeviceByDevNum(dev_num); + + if (dev_handle == NULL) + { + DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num); + break; + } + struct libusb_transfer *transfer = libusb_alloc_transfer(0); + transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; + + u8 * buffer = (u8*)malloc(wLength + LIBUSB_CONTROL_SETUP_SIZE); + libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength); + memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, Memory::GetPointer(data), wLength); + libusb_fill_control_transfer(transfer, dev_handle, buffer, handleUsbUpdates, (void*)(size_t)_CommandAddress, /* no timeout */ 0); + libusb_submit_transfer(transfer); + + //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Control)(%02X, %02X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + // bmRequestType, bRequest, BufferIn, BufferInSize, BufferOut, BufferOutSize); + + // It's the async way! + return false; + break; + } + case IOCTL_HID_INTERRUPT_OUT: + case IOCTL_HID_INTERRUPT_IN: + { + u32 dev_num = Memory::Read_U32(BufferIn+0x10); + u32 endpoint = Memory::Read_U32(BufferIn+0x14); + u32 length = Memory::Read_U32(BufferIn+0x18); + + u32 data = Memory::Read_U32(BufferIn+0x1C); + + ReturnValue = HIDERR_NO_DEVICE_FOUND; + + libusb_device_handle * dev_handle = GetDeviceByDevNum(dev_num); + + if (dev_handle == NULL) + { + DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num); + break; + } + + struct libusb_transfer *transfer = libusb_alloc_transfer(0); + transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; + libusb_fill_interrupt_transfer(transfer, dev_handle, endpoint, Memory::GetPointer(data), length, + handleUsbUpdates, (void*)(size_t)_CommandAddress, 0); + libusb_submit_transfer(transfer); + + //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Interrupt %s)(%d,%d,%X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + // Parameter == IOCTL_HID_INTERRUPT_IN ? "In" : "Out", endpoint, length, data, BufferIn, BufferInSize, BufferOut, BufferOutSize); + + // It's the async way! + return false; + break; + } + default: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(0x%x) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize); + break; + } + } + + Memory::Write_U32(ReturnValue, _CommandAddress + 4); + + return true; +} + + +bool CWII_IPC_HLE_Device_hid::ClaimDevice(libusb_device_handle * dev) +{ + int ret = 0; + if ((ret = libusb_kernel_driver_active(dev, 0)) == 1) + { + if ((ret = libusb_detach_kernel_driver(dev, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED) + { + DEBUG_LOG(WII_IPC_HID, "libusb_detach_kernel_driver failed with error: %d", ret); + return false; + } + } + else if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) + { + DEBUG_LOG(WII_IPC_HID, "libusb_kernel_driver_active error ret = %d", ret); + return false; + } + + if ((ret = libusb_claim_interface(dev, 0))) + { + DEBUG_LOG(WII_IPC_HID, "libusb_claim_interface failed with error: %d", ret); + return false; + } + + return true; +} + +bool CWII_IPC_HLE_Device_hid::IOCtlV(u32 _CommandAddress) +{ + + Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HID, LogTypes::LWARNING); + u32 ReturnValue = 0; + SIOCtlVBuffer CommandBuffer(_CommandAddress); + + DEBUG_LOG(WII_IPC_HID, "%s - IOCtlV:", GetDeviceName().c_str()); + DEBUG_LOG(WII_IPC_HID, " Parameter: 0x%x", CommandBuffer.Parameter); + DEBUG_LOG(WII_IPC_HID, " NumberIn: 0x%08x", CommandBuffer.NumberInBuffer); + DEBUG_LOG(WII_IPC_HID, " NumberOut: 0x%08x", CommandBuffer.NumberPayloadBuffer); + DEBUG_LOG(WII_IPC_HID, " BufferVector: 0x%08x", CommandBuffer.BufferVector); + DEBUG_LOG(WII_IPC_HID, " PayloadAddr: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Address); + DEBUG_LOG(WII_IPC_HID, " PayloadSize: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Size); + #if defined(_DEBUG) || defined(DEBUGFAST) + DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer); + #endif + + Memory::Write_U32(ReturnValue, _CommandAddress + 4); + return true; +} + + + +void CWII_IPC_HLE_Device_hid::ConvertDeviceToWii(WiiHIDDeviceDescriptor *dest, const struct libusb_device_descriptor *src) +{ + memcpy(dest,src,sizeof(WiiHIDDeviceDescriptor)); + dest->bcdUSB = Common::swap16(dest->bcdUSB); + dest->idVendor = Common::swap16(dest->idVendor); + dest->idProduct = Common::swap16(dest->idProduct); + dest->bcdDevice = Common::swap16(dest->bcdDevice); +} + +void CWII_IPC_HLE_Device_hid::ConvertConfigToWii(WiiHIDConfigDescriptor *dest, const struct libusb_config_descriptor *src) +{ + memcpy(dest,src,sizeof(WiiHIDConfigDescriptor)); + dest->wTotalLength = Common::swap16(dest->wTotalLength); +} + +void CWII_IPC_HLE_Device_hid::ConvertInterfaceToWii(WiiHIDInterfaceDescriptor *dest, const struct libusb_interface_descriptor *src) +{ + memcpy(dest,src,sizeof(WiiHIDInterfaceDescriptor)); +} + +void CWII_IPC_HLE_Device_hid::ConvertEndpointToWii(WiiHIDEndpointDescriptor *dest, const struct libusb_endpoint_descriptor *src) +{ + memcpy(dest,src,sizeof(WiiHIDEndpointDescriptor)); + dest->wMaxPacketSize = Common::swap16(dest->wMaxPacketSize); +} + +void CWII_IPC_HLE_Device_hid::FillOutDevices(u32 BufferOut, u32 BufferOutSize) +{ + static u16 check = 1; + int OffsetBuffer = BufferOut; + int OffsetStart = 0; + //int OffsetDevice = 0; + int d,c,ic,i,e; /* config, interface container, interface, endpoint */ + + libusb_device **list; + //libusb_device *found = NULL; + ssize_t cnt = libusb_get_device_list(NULL, &list); + DEBUG_LOG(WII_IPC_HID, "Found %ld viable USB devices.", cnt); + for (d = 0; d < cnt; d++) + { + libusb_device *device = list[d]; + struct libusb_device_descriptor desc; + int dRet = libusb_get_device_descriptor (device, &desc); + if (dRet) + { + // could not aquire the descriptor, no point in trying to use it. + DEBUG_LOG(WII_IPC_HID, "libusb_get_device_descriptor failed with error: %d", dRet); + continue; + } + OffsetStart = OffsetBuffer; + OffsetBuffer += 4; // skip length for now, fill at end + + OffsetBuffer += 4; // skip devNum for now + + WiiHIDDeviceDescriptor wii_device; + ConvertDeviceToWii(&wii_device, &desc); + Memory::WriteBigEData((const u8*)&wii_device, OffsetBuffer, Align(wii_device.bLength, 4)); + OffsetBuffer += Align(wii_device.bLength, 4); + bool deviceValid = true; + + for (c = 0; deviceValid && c < desc.bNumConfigurations; c++) + { + struct libusb_config_descriptor *config = NULL; + int cRet = libusb_get_config_descriptor(device, c, &config); + + // do not try to use usb devices with more than one interface, games can crash + if(cRet == 0 && config->bNumInterfaces <= MAX_HID_INTERFACES) + { + WiiHIDConfigDescriptor wii_config; + ConvertConfigToWii(&wii_config, config); + Memory::WriteBigEData((const u8*)&wii_config, OffsetBuffer, Align(wii_config.bLength, 4)); + OffsetBuffer += Align(wii_config.bLength, 4); + + for (ic = 0; ic < config->bNumInterfaces; ic++) + { + const struct libusb_interface *interfaceContainer = &config->interface[ic]; + for (i = 0; i < interfaceContainer->num_altsetting; i++) + { + const struct libusb_interface_descriptor *interface = &interfaceContainer->altsetting[i]; + + WiiHIDInterfaceDescriptor wii_interface; + ConvertInterfaceToWii(&wii_interface, interface); + Memory::WriteBigEData((const u8*)&wii_interface, OffsetBuffer, Align(wii_interface.bLength, 4)); + OffsetBuffer += Align(wii_interface.bLength, 4); + + for (e = 0; e < interface->bNumEndpoints; e++) + { + const struct libusb_endpoint_descriptor *endpoint = &interface->endpoint[e]; + + WiiHIDEndpointDescriptor wii_endpoint; + ConvertEndpointToWii(&wii_endpoint, endpoint); + Memory::WriteBigEData((const u8*)&wii_endpoint, OffsetBuffer, Align(wii_endpoint.bLength, 4)); + OffsetBuffer += Align(wii_endpoint.bLength, 4); + + } //endpoints + } // interfaces + } // interface containters + libusb_free_config_descriptor(config); + config = NULL; + } + else + { + if(cRet) + DEBUG_LOG(WII_IPC_HID, "libusb_get_config_descriptor failed with: %d", cRet); + deviceValid = false; + OffsetBuffer = OffsetStart; + } + } // configs + + if (deviceValid) + { + Memory::Write_U32(OffsetBuffer-OffsetStart, OffsetStart); // fill in length + + int devNum = GetAvaiableDevNum(desc.idVendor, + desc.idProduct, + libusb_get_bus_number (device), + libusb_get_device_address (device), + check); + if (devNum < 0 ) + { + // too many devices to handle. + ERROR_LOG(WII_IPC_HID, "Exhausted device list, you have way too many usb devices plugged in." + "Or it might be our fault. Let us know at https://code.google.com/p/dolphin-emu/issues/entry?template=Defect%%20report"); + OffsetBuffer = OffsetStart; + continue; + } + + DEBUG_LOG(WII_IPC_HID, "Found device with Vendor: %X Product: %X Devnum: %d", desc.idVendor, desc.idProduct, devNum); + + Memory::Write_U32(devNum , OffsetStart+4); //write device num + } + } + + // Find devices that no longer exists and free them + for (i=0; i> 48); + if(hidDeviceAliases[i] != 0 && check_cur != check) + { + DEBUG_LOG(WII_IPC_HID, "Removing: device %d %hX %hX", i, check, check_cur); + std::lock_guard lk(s_open_devices); + if (open_devices.find(i) != open_devices.end()) + { + libusb_device_handle *handle = open_devices[i]; + libusb_close(handle); + open_devices.erase(i); + } + hidDeviceAliases[i] = 0; + } + } + check++; + + + libusb_free_device_list(list, 1); + + Memory::Write_U32(0xFFFFFFFF, OffsetBuffer); // no more devices + +} + +int CWII_IPC_HLE_Device_hid::Align(int num, int alignment) +{ + return (num + (alignment-1)) & ~(alignment-1); +} + + +libusb_device_handle * CWII_IPC_HLE_Device_hid::GetDeviceByDevNum(u32 devNum) +{ + u32 i; + libusb_device **list; + libusb_device_handle *handle = NULL; + ssize_t cnt; + + if(devNum >= MAX_DEVICE_DEVNUM) + return NULL; + + + std::lock_guard lk(s_open_devices); + + if (open_devices.find(devNum) != open_devices.end()) + { + handle = open_devices[devNum]; + if(libusb_kernel_driver_active(handle, 0) != LIBUSB_ERROR_NO_DEVICE) + { + return handle; + } + else + { + libusb_close(handle); + open_devices.erase(devNum); + } + } + + cnt = libusb_get_device_list(NULL, &list); + + if (cnt < 0) + return NULL; + + for (i = 0; i < cnt; i++) { + libusb_device *device = list[i]; + struct libusb_device_descriptor desc; + int dRet = libusb_get_device_descriptor (device, &desc); + u8 bus = libusb_get_bus_number (device); + u8 port = libusb_get_device_address (device); + u64 unique_id = ((u64)desc.idVendor << 32) | ((u64)desc.idProduct << 16) | ((u64)bus << 8) | (u64)port; + if ((hidDeviceAliases[devNum] & HID_ID_MASK) == unique_id) + { + int ret = libusb_open(device, &handle); + if (ret) + { + if (ret == LIBUSB_ERROR_ACCESS) + { + if( dRet ) + { + ERROR_LOG(WII_IPC_HID, "Dolphin does not have access to this device: Bus %03d Device %03d: ID ????:???? (couldn't get id).", + bus, + port + ); + } + else{ + ERROR_LOG(WII_IPC_HID, "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.", + bus, + port, + desc.idVendor, + desc.idProduct + ); + } + } +#ifdef _WIN32 + else if (ret == LIBUSB_ERROR_NOT_SUPPORTED) + { + WARN_LOG(WII_IPC_HID, "Please install the libusb drivers for the device %04X:%04X", desc.idVendor, desc.idProduct); + } +#endif + else + { + ERROR_LOG(WII_IPC_HID, "libusb_open failed to open device with error = %d", ret); + } + continue; + } + + + if (!ClaimDevice(handle)) + { + ERROR_LOG(WII_IPC_HID, "Could not claim the device for handle: %X", devNum); + libusb_close(handle); + continue; + } + + open_devices[devNum] = handle; + break; + } + else + { + handle = NULL; + } + } + + libusb_free_device_list(list, 1); + + + return handle; +} + + +int CWII_IPC_HLE_Device_hid::GetAvaiableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, u16 check) +{ + int i; + int pos = -1; + u64 unique_id = ((u64)idVendor << 32) | ((u64)idProduct << 16) | ((u64)bus << 8) | (u64)port; + for (i=0; i + +#define HID_ID_MASK 0x0000FFFFFFFFFFFF +#define MAX_HID_INTERFACES 1 + +#define HIDERR_NO_DEVICE_FOUND -4 + +/* Connection timed out */ + +class CWII_IPC_HLE_Device_hid : public IWII_IPC_HLE_Device +{ +public: + CWII_IPC_HLE_Device_hid(u32 _DeviceID, const std::string& _rDeviceName); + + virtual ~CWII_IPC_HLE_Device_hid(); + + virtual bool Open(u32 _CommandAddress, u32 _Mode); + virtual bool Close(u32 _CommandAddress, bool _bForce); + virtual u32 Update(); + + virtual bool IOCtlV(u32 _CommandAddress); + virtual bool IOCtl(u32 _CommandAddress); +private: + + + enum + { + IOCTL_HID_GET_ATTACHED = 0x00, + IOCTL_HID_SET_SUSPEND = 0x01, + IOCTL_HID_CONTROL = 0x02, + IOCTL_HID_INTERRUPT_IN = 0x03, + IOCTL_HID_INTERRUPT_OUT = 0x04, + IOCTL_HID_GET_US_STRING = 0x05, + IOCTL_HID_OPEN = 0x06, + IOCTL_HID_SHUTDOWN = 0x07, + IOCTL_HID_CANCEL_INTERRUPT = 0x08, + }; + + /* Device descriptor */ + typedef struct + { + u8 bLength; + u8 bDescriptorType; + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize0; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; + u8 pad[2]; + } WiiHIDDeviceDescriptor; + + typedef struct + { + u8 bLength; + u8 bDescriptorType; + u16 wTotalLength; + u8 bNumInterfaces; + u8 bConfigurationValue; + u8 iConfiguration; + u8 bmAttributes; + u8 MaxPower; + u8 pad[3]; + } WiiHIDConfigDescriptor; + + typedef struct + { + u8 bLength; + u8 bDescriptorType; + u8 bInterfaceNumber; + u8 bAlternateSetting; + u8 bNumEndpoints; + u8 bInterfaceClass; + u8 bInterfaceSubClass; + u8 bInterfaceProtocol; + u8 iInterface; + u8 pad[3]; + } WiiHIDInterfaceDescriptor; + + typedef struct + { + u8 bLength; + u8 bDescriptorType; + u8 bEndpointAddress; + u8 bmAttributes; + u16 wMaxPacketSize; + u8 bInterval; + u8 bRefresh; + u8 bSynchAddress; + u8 pad[1]; + } WiiHIDEndpointDescriptor; + + + u32 deviceCommandAddress; + void FillOutDevices(u32 BufferOut, u32 BufferOutSize); + int GetAvaiableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, u16 check); + + bool ClaimDevice(libusb_device_handle * dev); + + void ConvertDeviceToWii(WiiHIDDeviceDescriptor *dest, const struct libusb_device_descriptor *src); + void ConvertConfigToWii(WiiHIDConfigDescriptor *dest, const struct libusb_config_descriptor *src); + void ConvertInterfaceToWii(WiiHIDInterfaceDescriptor *dest, const struct libusb_interface_descriptor *src); + void ConvertEndpointToWii(WiiHIDEndpointDescriptor *dest, const struct libusb_endpoint_descriptor *src); + + int Align(int num, int alignment); + static void checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid); + static void LIBUSB_CALL handleUsbUpdates(struct libusb_transfer *transfer); + + struct libusb_device_handle * GetDeviceByDevNum(u32 devNum); + std::map open_devices; + std::mutex s_open_devices; + std::map device_identifiers; + + std::thread usb_thread; + bool usb_thread_running; + + typedef struct + { + u32 enq_address; + u32 type; + void * context; + } _hidevent; + + std::list<_hidevent> event_list; +}; diff --git a/Source/VSProps/Dolphin.Win32.props b/Source/VSProps/Dolphin.Win32.props index c3edb136b6..7ffd5a3037 100644 --- a/Source/VSProps/Dolphin.Win32.props +++ b/Source/VSProps/Dolphin.Win32.props @@ -7,8 +7,8 @@ - ..\..\..\Externals\SDL\$(PlatformName);..\..\..\Externals\GLew;..\..\..\Externals\Cg;..\..\..\Externals\portaudio\$(PlatformName)\$(ConfigurationName);..\..\..\Externals\openssl\$(PlatformName) - portaudio.lib;dsound.lib;dxerr.lib;iphlpapi.lib;winmm.lib;setupapi.lib;xinput.lib;vfw32.lib;cg.lib;cgGL.lib;opengl32.lib;glew32s.lib;glu32.lib;rpcrt4.lib;comctl32.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies) + ..\..\..\Externals\SDL\$(PlatformName);..\..\..\Externals\GLew;..\..\..\Externals\Cg;..\..\..\Externals\portaudio\$(PlatformName)\$(ConfigurationName);..\..\..\Externals\openssl\$(PlatformName);..\..\..\Externals\libusb\$(PlatformName) + libusb-1.0.lib;portaudio.lib;dsound.lib;dxerr.lib;iphlpapi.lib;winmm.lib;setupapi.lib;xinput.lib;vfw32.lib;cg.lib;cgGL.lib;opengl32.lib;glew32s.lib;glu32.lib;rpcrt4.lib;comctl32.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies) diff --git a/Source/VSProps/Dolphin.x64.props b/Source/VSProps/Dolphin.x64.props index b7ad7e5f09..e9591c4fdb 100644 --- a/Source/VSProps/Dolphin.x64.props +++ b/Source/VSProps/Dolphin.x64.props @@ -8,8 +8,8 @@ - ..\..\..\Externals\SDL\$(PlatformName);..\..\..\Externals\GLew;..\..\..\Externals\Cg64;..\..\..\Externals\portaudio\$(PlatformName)\$(ConfigurationName);..\..\..\Externals\openssl\$(PlatformName) - portaudio.lib;dsound.lib;dxerr.lib;iphlpapi.lib;winmm.lib;setupapi.lib;xinput.lib;vfw32.lib;cg.lib;cgGL.lib;opengl32.lib;glew64s.lib;glu32.lib;rpcrt4.lib;comctl32.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies) + ..\..\..\Externals\SDL\$(PlatformName);..\..\..\Externals\GLew;..\..\..\Externals\Cg64;..\..\..\Externals\portaudio\$(PlatformName)\$(ConfigurationName);..\..\..\Externals\openssl\$(PlatformName);..\..\..\Externals\libusb\$(PlatformName) + libusb-1.0.lib;portaudio.lib;dsound.lib;dxerr.lib;iphlpapi.lib;winmm.lib;setupapi.lib;xinput.lib;vfw32.lib;cg.lib;cgGL.lib;opengl32.lib;glew64s.lib;glu32.lib;rpcrt4.lib;comctl32.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies)