Windows: Support LIBUSB_TRANSFER_ADD_ZERO_PACKET on winusb
authorPatrick Stewart <patrick@rfcreations.com>
Fri, 9 Jun 2017 19:54:45 +0000 (20:54 +0100)
committerNathan Hjelm <hjelmn@google.com>
Tue, 8 Jun 2021 03:08:40 +0000 (21:08 -0600)
Closes #312

Signed-off-by: Nathan Hjelm <hjelmn@google.com>
libusb/os/windows_common.h
libusb/os/windows_winusb.c
libusb/version_nano.h

index c84f1f9f70429430e9bae90d447a53c245a47997..2de2b6016e64c02fde4f4b8fc63319c56b6f36d6 100644 (file)
@@ -265,12 +265,19 @@ struct usbdk_device_handle_priv {
        // Not currently used
        char dummy;
 };
+enum WINUSB_ZLP {
+       WINUSB_ZLP_UNSET = 0,
+       WINUSB_ZLP_OFF = 1,
+       WINUSB_ZLP_ON = 2
+};
 
 struct winusb_device_handle_priv {
        int active_interface;
        struct {
                HANDLE dev_handle; // WinUSB needs an extra handle for the file
                HANDLE api_handle; // used by the API to communicate with the device
+               uint8_t zlp[USB_MAXENDPOINTS]; // Current per-endpoint SHORT_PACKET_TERMINATE status (enum WINUSB_ZLP)
        } interface_handle[USB_MAXINTERFACES];
        int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
 };
index e4d194a330135da6d2e406fbd6fa883a22635286..877a2ab3710b64dbff7fa46fe32ec06249ba6cbe 100644 (file)
@@ -2024,8 +2024,6 @@ static int winusb_submit_transfer(struct usbi_transfer *itransfer)
                break;
        case LIBUSB_TRANSFER_TYPE_BULK:
        case LIBUSB_TRANSFER_TYPE_INTERRUPT:
-               if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
-                       return LIBUSB_ERROR_NOT_SUPPORTED;
                transfer_fn = priv->apib->submit_bulk_transfer;
                break;
        case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
@@ -2474,6 +2472,7 @@ static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle
                        continue; // Other policies don't apply to control endpoint or libusb0
 
                policy = false;
+               handle_priv->interface_handle[iface].zlp[endpoint_address] = WINUSB_ZLP_UNSET;
                if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
                        SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy))
                        usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address);
@@ -3041,6 +3040,23 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran
                usbi_dbg("reading %d bytes", transfer->length);
                ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
        } else {
+               // Set SHORT_PACKET_TERMINATE if ZLP requested.
+               // Changing this can be a problem with packets in flight, so only allow on the first transfer.
+               UCHAR policy = (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) != 0;
+               uint8_t* current_zlp = &handle_priv->interface_handle[current_interface].zlp[transfer->endpoint];
+               if (*current_zlp == WINUSB_ZLP_UNSET) {
+                       if (policy &&
+                               !WinUSBX[sub_api].SetPipePolicy(winusb_handle, transfer->endpoint,
+                               SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) {
+                               usbi_err(TRANSFER_CTX(transfer), "failed to set SHORT_PACKET_TERMINATE for endpoint %02X", transfer->endpoint);
+                               return LIBUSB_ERROR_NOT_SUPPORTED;
+                       }
+                       *current_zlp = policy ? WINUSB_ZLP_ON : WINUSB_ZLP_OFF;
+               } else if (policy != (*current_zlp == WINUSB_ZLP_ON)) {
+                       usbi_err(TRANSFER_CTX(transfer), "cannot change ZERO_PACKET for endpoint %02X on Windows", transfer->endpoint);
+                       return LIBUSB_ERROR_NOT_SUPPORTED;
+               }
+
                usbi_dbg("writing %d bytes", transfer->length);
                ret = WinUSBX[sub_api].WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
        }
@@ -4006,6 +4022,9 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer
        UNUSED(sub_api);
        CHECK_HID_AVAILABLE;
 
+       if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
+               return LIBUSB_ERROR_NOT_SUPPORTED;
+
        transfer_priv->hid_dest = NULL;
        safe_free(transfer_priv->hid_buffer);
 
index f8f80a37bd3a6476e79e2af98f63141501fc0d78..53d05fe9f6bf6513d56d5ab6852dbe4d610b0547 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 11620
+#define LIBUSB_NANO 11621