示例#1
0
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;
    }
}