From 55ced7746dd697024f2042aca009b7436892bf2b Mon Sep 17 00:00:00 2001 From: Joshua Blake Date: Sat, 30 Nov 2013 06:18:29 -0500 Subject: Windows: Added isochronous support via libusbk [dickens] Rebased against latest changes and fixed some styling issues Closes #246 Signed-off-by: Chris Dickens --- libusb/os/windows_nt_shared_types.h | 1 + libusb/os/windows_winusb.c | 103 +++++++++++++++++++++++++++++++++++- libusb/os/windows_winusb.h | 42 +++++++++++++++ libusb/version_nano.h | 2 +- 4 files changed, 146 insertions(+), 2 deletions(-) diff --git a/libusb/os/windows_nt_shared_types.h b/libusb/os/windows_nt_shared_types.h index 1f5cfbd..68bf261 100644 --- a/libusb/os/windows_nt_shared_types.h +++ b/libusb/os/windows_nt_shared_types.h @@ -134,4 +134,5 @@ struct winusb_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; + void *iso_context; }; diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c index b07e67a..ff86db6 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); @@ -1734,6 +1735,8 @@ static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer) transfer_priv->pollable_fd = INVALID_WINFD; transfer_priv->handle = NULL; safe_free(transfer_priv->hid_buffer); + safe_free(transfer_priv->iso_context); + // When auto claim is in use, attempt to release the auto-claimed interface auto_release(itransfer); } @@ -1966,7 +1969,7 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { winusbx_clear_halt, winusbx_reset_device, winusbx_submit_bulk_transfer, - NULL, /* submit_iso_transfer */ + winusbx_submit_iso_transfer, winusbx_submit_control_transfer, winusbx_abort_control, winusbx_abort_transfers, @@ -2059,6 +2062,8 @@ static int winusbx_init(struct libusb_context *ctx) WinUSBX_Set(SetCurrentAlternateSetting); WinUSBX_Set(SetPipePolicy); WinUSBX_Set(WritePipe); + WinUSBX_Set(IsoReadPipe); + WinUSBX_Set(IsoWritePipe); if (WinUSBX[i].Initialize != NULL) { WinUSBX[i].initialized = true; @@ -2473,6 +2478,78 @@ 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 winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + HANDLE winusb_handle; + OVERLAPPED *overlapped; + bool ret; + int current_interface; + int i; + UINT offset; + PKISO_CONTEXT iso_context; + size_t iso_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 + PRINT_UNSUPPORTED_API(submit_iso_transfer); + }; + + 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); + + transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + overlapped = transfer_priv->pollable_fd.overlapped; + + iso_ctx_size = sizeof(KISO_CONTEXT) + (transfer->num_iso_packets * sizeof(KISO_PACKET)); + transfer_priv->iso_context = iso_context = calloc(1, iso_ctx_size); + if (transfer_priv->iso_context == NULL) + return LIBUSB_ERROR_NO_MEM; + + // start ASAP + iso_context->StartFrame = 0; + iso_context->NumberOfPackets = (SHORT)transfer->num_iso_packets; + + // convert the transfer packet lengths to iso_packet offsets + offset = 0; + for (i = 0; i < transfer->num_iso_packets; i++) { + 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(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context); + } else { + usbi_dbg("writing %d iso packets", transfer->num_iso_packets); + ret = WinUSBX[sub_api].IsoWritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context); + } + + if (!ret) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_err(ctx, "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; + } + } else { + windows_force_sync_completion(overlapped, (ULONG)transfer->length); + } + + 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); @@ -2654,6 +2731,30 @@ 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 winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + PKISO_CONTEXT iso_context; + int i; + + if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { + CHECK_WINUSBX_AVAILABLE(sub_api); + + // 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 + iso_context = transfer_priv->iso_context; + for (i = 0; i < transfer->num_iso_packets; i++) { + transfer->iso_packet_desc[i].actual_length = 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 + PRINT_UNSUPPORTED_API(copy_transfer_data); + } + } + itransfer->transferred += io_size; return LIBUSB_TRANSFER_COMPLETED; } diff --git a/libusb/os/windows_winusb.h b/libusb/os/windows_winusb.h index 9b4a0f6..3bdf185 100644 --- a/libusb/os/windows_winusb.h +++ b/libusb/os/windows_winusb.h @@ -554,6 +554,46 @@ typedef VOID (WINAPI *LibK_GetVersion_t)( PKLIB_VERSION Version ); +//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, *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, *PKISO_CONTEXT; + +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 +); + struct winusb_interface { bool initialized; WinUsb_AbortPipe_t AbortPipe; @@ -568,6 +608,8 @@ struct winusb_interface { WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting; WinUsb_SetPipePolicy_t SetPipePolicy; WinUsb_WritePipe_t WritePipe; + WinUsb_IsoReadPipe_t IsoReadPipe; + WinUsb_IsoWritePipe_t IsoWritePipe; }; /* hid.dll interface */ diff --git a/libusb/version_nano.h b/libusb/version_nano.h index 203581d..f2e6efa 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11286 +#define LIBUSB_NANO 11287 -- cgit v1.2.1