From cd9d32721d4a200cf04520175eaafd84ee1c8f31 Mon Sep 17 00:00:00 2001 From: jasjuang Date: Sat, 18 Nov 2017 16:07:49 -0800 Subject: [PATCH] [libusb] apply patch to make it libfreenect2 compatible --- ports/libusb/libfreenect2.patch | 268 ++++++++++++++++++++++++++++++++ ports/libusb/portfile.cmake | 5 + 2 files changed, 273 insertions(+) create mode 100644 ports/libusb/libfreenect2.patch diff --git a/ports/libusb/libfreenect2.patch b/ports/libusb/libfreenect2.patch new file mode 100644 index 0000000000..2c2b859b01 --- /dev/null +++ b/ports/libusb/libfreenect2.patch @@ -0,0 +1,268 @@ +diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c +index 93668f3..7fdafd6 100644 +--- a/libusb/os/windows_winusb.c ++++ b/libusb/os/windows_winusb.c +@@ -66,6 +66,7 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev + static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); + static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); + static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); ++static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer); + static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); + static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); + static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer); +@@ -1901,6 +1902,10 @@ void windows_clear_transfer_priv(struct usbi_transfer *itransfer) + + usbi_free_fd(&transfer_priv->pollable_fd); + safe_free(transfer_priv->hid_buffer); ++ ++ //TODO this should occur during windows_free_transfer instead ++ safe_free(transfer_priv->iso_context); ++ + // When auto claim is in use, attempt to release the auto-claimed interface + auto_release(itransfer); + } +@@ -2274,7 +2279,7 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { + winusbx_clear_halt, + winusbx_reset_device, + winusbx_submit_bulk_transfer, +- unsupported_submit_iso_transfer, ++ winusbx_submit_iso_transfer, + winusbx_submit_control_transfer, + winusbx_abort_control, + winusbx_abort_transfers, +@@ -2374,6 +2379,8 @@ static int winusbx_init(int sub_api, struct libusb_context *ctx) + WinUSBX_Set(SetPipePolicy); + WinUSBX_Set(SetPowerPolicy); + WinUSBX_Set(WritePipe); ++ WinUSBX_Set(IsoReadPipe); ++ WinUSBX_Set(IsoWritePipe); + if (!native_winusb) + WinUSBX_Set(ResetDevice); + +@@ -2803,6 +2810,100 @@ static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_ha + return LIBUSB_SUCCESS; + } + ++static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) ++{ ++ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); ++ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); ++ struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); ++ struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); ++ struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); ++ HANDLE winusb_handle; ++ bool ret; ++ int current_interface; ++ struct winfd wfd; ++ int i; ++ uint16_t maxPacketSize; ++ uint32_t offset; ++ size_t ctx_size; ++ ++ CHECK_WINUSBX_AVAILABLE(sub_api); ++ ++ if (sub_api != SUB_API_LIBUSBK && sub_api != SUB_API_LIBUSB0) ++ { ++ //iso only supported on libusbk-based backends ++ return unsupported_submit_iso_transfer(sub_api, itransfer); ++ }; ++ ++ transfer_priv->pollable_fd = INVALID_WINFD; ++ ++ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); ++ if (current_interface < 0) { ++ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); ++ return LIBUSB_ERROR_NOT_FOUND; ++ } ++ ++ usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); ++ ++ winusb_handle = handle_priv->interface_handle[current_interface].api_handle; ++ ++ wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL); ++ // Always use the handle returned from usbi_create_fd (wfd.handle) ++ if (wfd.fd < 0) { ++ return LIBUSB_ERROR_NO_MEM; ++ } ++ ++ ctx_size = sizeof(KISO_CONTEXT)+sizeof(KISO_PACKET)* transfer->num_iso_packets; ++ //Init the libusbk iso_context ++ if (!transfer_priv->iso_context) ++ { ++ transfer_priv->iso_context = (PKISO_CONTEXT)malloc(ctx_size); ++ if (!transfer_priv->iso_context) ++ { ++ //TODO does this return leak mem, or does the transfer get cleaned up? ++ return LIBUSB_ERROR_NO_MEM; ++ } ++ } ++ memset(transfer_priv->iso_context, 0, ctx_size); ++ ++ //start ASAP ++ transfer_priv->iso_context->StartFrame = 0; ++ transfer_priv->iso_context->NumberOfPackets = transfer->num_iso_packets; ++ ++ /* convert the transfer packet lengths to iso_packet offsets */ ++ offset = 0; ++ for (i = 0; i < transfer->num_iso_packets; i++) ++ { ++ transfer_priv->iso_context->IsoPackets[i].offset = offset; ++ offset += transfer->iso_packet_desc[i].length; ++ } ++ ++ if (IS_XFERIN(transfer)) { ++ usbi_dbg("reading %d iso packets", transfer->num_iso_packets); ++ ret = WinUSBX[sub_api].IsoReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, wfd.overlapped, transfer_priv->iso_context); ++ } ++ else { ++ usbi_dbg("writing %d iso packets", transfer->num_iso_packets); ++ ret = WinUSBX[sub_api].IsoWritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, wfd.overlapped, transfer_priv->iso_context); ++ } ++ ++ if (!ret) { ++ if (GetLastError() != ERROR_IO_PENDING) { ++ usbi_err(ctx, "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0)); ++ usbi_free_fd(&wfd); ++ return LIBUSB_ERROR_IO; ++ } ++ } ++ else { ++ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; ++ wfd.overlapped->InternalHigh = (DWORD)transfer->length; ++ } ++ ++ transfer_priv->pollable_fd = wfd; ++ transfer_priv->interface_number = (uint8_t)current_interface; ++ ++ return LIBUSB_SUCCESS; ++} ++ + static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) + { + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); +@@ -2989,7 +3090,36 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha + + static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) + { ++ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); ++ struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); ++ struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); ++ int i; ++ ++ CHECK_WINUSBX_AVAILABLE(sub_api); ++ ++ if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) ++ { ++ //for isochronous, need to copy the individual iso packet actual_lengths and statuses ++ if (sub_api == SUB_API_LIBUSBK || sub_api == SUB_API_LIBUSB0) ++ { ++ //iso only supported on libusbk-based backends for now ++ ++ for (i = 0; i < transfer->num_iso_packets; i++) ++ { ++ transfer->iso_packet_desc[i].actual_length = transfer_priv->iso_context->IsoPackets[i].actual_length; ++ //TODO translate USDB_STATUS codes http://msdn.microsoft.com/en-us/library/ff539136(VS.85).aspx to libusb_transfer_status ++ //transfer->iso_packet_desc[i].status = transfer_priv->iso_context->IsoPackets[i].status; ++ } ++ } ++ else ++ { ++ //This should only occur if backend is not set correctly or other backend isoc is partially implemented ++ return unsupported_copy_transfer_data(sub_api, itransfer, io_size); ++ } ++ } ++ + itransfer->transferred += io_size; ++ + return LIBUSB_TRANSFER_COMPLETED; + } + +diff --git a/libusb/os/windows_winusb.h b/libusb/os/windows_winusb.h +index 89ebc24..28a7e4f 100644 +--- a/libusb/os/windows_winusb.h ++++ b/libusb/os/windows_winusb.h +@@ -154,6 +154,42 @@ struct libusb_hid_descriptor { + #define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN) + #define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type)) + ++ ++/* start libusbk_shared.h definitions, must match libusbk_shared.h for isochronous support */ ++ ++//KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths ++typedef struct _KISO_PACKET ++{ ++ UINT offset; ++ USHORT actual_length; //changed from libusbk_shared.h "Length" for clarity ++ USHORT status; ++ ++} KISO_PACKET; ++ ++typedef KISO_PACKET* PKISO_PACKET; ++ ++typedef enum _KISO_FLAG ++{ ++ KISO_FLAG_NONE = 0, ++ KISO_FLAG_SET_START_FRAME = 0x00000001, ++} KISO_FLAG; ++ ++//KISO_CONTEXT is the conceptual equivalent of libusb_transfer except is isochronous-specific and must match libusbk's version ++typedef struct _KISO_CONTEXT ++{ ++ KISO_FLAG Flags; ++ UINT StartFrame; ++ SHORT ErrorCount; ++ SHORT NumberOfPackets; ++ UINT UrbHdrStatus; ++ KISO_PACKET IsoPackets[0]; ++ ++} KISO_CONTEXT; ++ ++typedef KISO_CONTEXT* PKISO_CONTEXT; ++ ++/* end libusbk_shared.h definitions */ ++ + // The following are used for HID reports IOCTLs + #define HID_CTL_CODE(id) \ + CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS) +@@ -280,6 +316,8 @@ struct windows_transfer_priv { + uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID + uint8_t *hid_dest; // transfer buffer destination, required for HID + size_t hid_expected_size; ++ /* Isoc */ ++ PKISO_CONTEXT iso_context; + }; + + // used to match a device driver (including filter drivers) against a supported API +@@ -623,6 +661,23 @@ typedef BOOL (WINAPI *WinUsb_ResetDevice_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle + ); + ++typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)( ++ WINUSB_INTERFACE_HANDLE InterfaceHandle, ++ UCHAR PipeID, ++ PUCHAR Buffer, ++ ULONG BufferLength, ++ LPOVERLAPPED Overlapped, ++ PKISO_CONTEXT IsoContext ++ ); ++typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)( ++ WINUSB_INTERFACE_HANDLE InterfaceHandle, ++ UCHAR PipeID, ++ PUCHAR Buffer, ++ ULONG BufferLength, ++ LPOVERLAPPED Overlapped, ++ PKISO_CONTEXT IsoContext ++ ); ++ + /* /!\ These must match the ones from the official libusbk.h */ + typedef enum _KUSB_FNID { + KUSB_FNID_Init, +@@ -703,6 +758,8 @@ struct winusb_interface { + WinUsb_SetPowerPolicy_t SetPowerPolicy; + WinUsb_WritePipe_t WritePipe; + WinUsb_ResetDevice_t ResetDevice; ++ WinUsb_IsoReadPipe_t IsoReadPipe; ++ WinUsb_IsoWritePipe_t IsoWritePipe; + }; + + /* hid.dll interface */ diff --git a/ports/libusb/portfile.cmake b/ports/libusb/portfile.cmake index 398fdcfd15..cd99405e69 100644 --- a/ports/libusb/portfile.cmake +++ b/ports/libusb/portfile.cmake @@ -16,6 +16,11 @@ vcpkg_from_github( HEAD_REF master ) +vcpkg_apply_patches( + SOURCE_PATH ${SOURCE_PATH} + PATCHES "${CMAKE_CURRENT_LIST_DIR}/libfreenect2.patch" +) + if (TRIPLET_SYSTEM_ARCH MATCHES "x86") set(MSBUILD_PLATFORM "Win32") else ()