static void wince_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer); struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev); int status; usbi_dbg("handling I/O completion with errcode %d", io_result); if (io_result == ERROR_NOT_SUPPORTED && transfer->type != LIBUSB_TRANSFER_TYPE_CONTROL) { /* For functional stalls, the WinCE USB layer (and therefore the USB Kernel Wrapper * Driver) will report USB_ERROR_STALL/ERROR_NOT_SUPPORTED in situations where the * endpoint isn't actually stalled. * * One example of this is that some devices will occasionally fail to reply to an IN * token. The WinCE USB layer carries on with the transaction until it is completed * (or cancelled) but then completes it with USB_ERROR_STALL. * * This code therefore needs to confirm that there really is a stall error, by both * checking the pipe status and requesting the endpoint status from the device. */ BOOL halted = FALSE; usbi_dbg("checking I/O completion with errcode ERROR_NOT_SUPPORTED is really a stall"); if (UkwIsPipeHalted(priv->dev, transfer->endpoint, &halted)) { /* Pipe status retrieved, so now request endpoint status by sending a GET_STATUS * control request to the device. This is done synchronously, which is a bit * naughty, but this is a special corner case. */ WORD wStatus = 0; DWORD written = 0; UKW_CONTROL_HEADER ctrlHeader; ctrlHeader.bmRequestType = LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_ENDPOINT; ctrlHeader.bRequest = LIBUSB_REQUEST_GET_STATUS; ctrlHeader.wValue = 0; ctrlHeader.wIndex = transfer->endpoint; ctrlHeader.wLength = sizeof(wStatus); if (UkwIssueControlTransfer(priv->dev, UKW_TF_IN_TRANSFER | UKW_TF_SEND_TO_ENDPOINT, &ctrlHeader, &wStatus, sizeof(wStatus), &written, NULL)) { if (written == sizeof(wStatus) && (wStatus & STATUS_HALT_FLAG) == 0) { if (!halted || UkwClearHaltHost(priv->dev, transfer->endpoint)) { usbi_dbg("Endpoint doesn't appear to be stalled, overriding error with success"); io_result = ERROR_SUCCESS; } else { usbi_dbg("Endpoint doesn't appear to be stalled, but the host is halted, changing error"); io_result = ERROR_IO_DEVICE; } } } } } switch(io_result) { case ERROR_SUCCESS: itransfer->transferred += io_size; status = LIBUSB_TRANSFER_COMPLETED; break; case ERROR_CANCELLED: usbi_dbg("detected transfer cancel"); status = LIBUSB_TRANSFER_CANCELLED; break; case ERROR_NOT_SUPPORTED: case ERROR_GEN_FAILURE: usbi_dbg("detected endpoint stall"); status = LIBUSB_TRANSFER_STALL; break; case ERROR_SEM_TIMEOUT: usbi_dbg("detected semaphore timeout"); status = LIBUSB_TRANSFER_TIMED_OUT; break; case ERROR_OPERATION_ABORTED: if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) { usbi_dbg("detected timeout"); status = LIBUSB_TRANSFER_TIMED_OUT; } else { usbi_dbg("detected operation aborted"); status = LIBUSB_TRANSFER_CANCELLED; } break; default: usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(io_result)); status = LIBUSB_TRANSFER_ERROR; break; } wince_clear_transfer_priv(itransfer); if (status == LIBUSB_TRANSFER_CANCELLED) { usbi_handle_transfer_cancellation(itransfer); } else { usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status); } }
static void performHaltOperation(char line[]) { char* linePtr = line + 1; // Parse the device index DWORD devIdx = 0; linePtr = parseNumber(linePtr, devIdx); if (!linePtr) { printf("Please provide a decimal device number following the command\n"); return; } DWORD endpoint = 0; linePtr = parseNumber(linePtr, endpoint); if (!linePtr) { printf("Please provide a decimal endpoint number following the command\n"); return; } if (devIdx >= gDeviceListSize || devIdx < 0) { printf("Invalid device index '%d' provided\n", devIdx); return; } if (endpoint >= UCHAR_MAX || endpoint < 0) { printf("Invalid endpoint '%d' provided\n", endpoint); return; } UKW_DEVICE device = gDeviceList[devIdx]; UCHAR ep = static_cast<UCHAR>(endpoint); switch (line[0]) { case 'q': { BOOL halted = FALSE; BOOL result = UkwIsPipeHalted(device, ep, &halted); if (!result) { printf("Failed to retrieve pipe halted status on endpoint %d on device %d: %d\n", ep, devIdx, GetLastError()); } else { printf("Halted status on endpoint %d on device %d is %d\n", ep, devIdx, halted); } break; } case 'c': { BOOL result = UkwClearHaltHost(device, ep); if (!result) { printf("Failed to clear halt/stall (host) on endpoint %d on device %d: %d\n", ep, devIdx, GetLastError()); } else { printf("Cleared halt/stall (host) on endpoint %d successfully\n", ep); } break; } case 's': { BOOL result = UkwClearHaltDevice(device, ep); if (!result) { printf("Failed to clear halt/stall (device) on endpoint %d on device %d: %d\n", ep, devIdx, GetLastError()); } else { printf("Cleared halt/stall (device) on endpoint %d successfully\n", ep); } break; } default: printf("Unknown halt operation provided\n"); break; } }