summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Blake <joshblake@gmail.com>2013-11-30 06:18:29 -0500
committerChris Dickens <christopher.a.dickens@gmail.com>2018-01-08 21:55:47 -0800
commit55ced7746dd697024f2042aca009b7436892bf2b (patch)
treee97aa3079aaee988cdce42c4ba2834a983a79873
parentca0b6c09fac0d9144b5397cbf6cca3615ed085eb (diff)
downloadlibusb-55ced7746dd697024f2042aca009b7436892bf2b.tar.gz
Windows: Added isochronous support via libusbk
[dickens] Rebased against latest changes and fixed some styling issues Closes #246 Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
-rw-r--r--libusb/os/windows_nt_shared_types.h1
-rw-r--r--libusb/os/windows_winusb.c103
-rw-r--r--libusb/os/windows_winusb.h42
-rw-r--r--libusb/version_nano.h2
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