Exemplo n.º 1
0
static int wince_submit_control_or_bulk_transfer(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 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);
	BOOL direction_in, ret;
	struct winfd wfd;
	DWORD flags;
	HANDLE eventHandle;
	PUKW_CONTROL_HEADER setup = NULL;
	const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;

	transfer_priv->pollable_fd = INVALID_WINFD;
	if (control_transfer) {
		setup = (PUKW_CONTROL_HEADER) transfer->buffer;
		direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
	} else {
		direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
	}
	flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
	flags |= UKW_TF_SHORT_TRANSFER_OK;

	eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (eventHandle == NULL) {
		usbi_err(ctx, "Failed to create event for async transfer");
		return LIBUSB_ERROR_NO_MEM;
	}

	wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer);
	if (wfd.fd < 0) {
		CloseHandle(eventHandle);
		return LIBUSB_ERROR_NO_MEM;
	}

	transfer_priv->pollable_fd = wfd;
	if (control_transfer) {
		// Split out control setup header and data buffer
		DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
		PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];

		ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, &transfer->actual_length, wfd.overlapped);
	} else {
		ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer, 
			transfer->length, &transfer->actual_length, wfd.overlapped);
	}
	if (!ret) {
		int libusbErr = translate_driver_error(GetLastError());
		usbi_err(ctx, "UkwIssue%sTransfer failed: error %d",
			control_transfer ? "Control" : "Bulk", GetLastError());
		wince_clear_transfer_priv(itransfer);
		return libusbErr;
	}
	usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
	itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;

	return LIBUSB_SUCCESS;
}
Exemplo n.º 2
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);
	}
}
Exemplo n.º 3
0
// Attempts to request a device switches into Android Accessory Protocol mode.
// See: http://developer.android.com/guide/topics/usb/adk.html#accessory-protocol
static void sendAapRequest(char line[])
{
    // Parse the device index
    DWORD devIdx = 0;
    line = parseNumber(line, devIdx);
    if (!line) {
        printf("Please provide a decimal device number following the command\n");
        return;
    }
    if (devIdx >= gDeviceListSize || devIdx < 0) {
        printf("Invalid device index '%d' provided\n", devIdx);
        return;
    }

    // Input validated so form the request
    UKW_DEVICE device = gDeviceList[devIdx];
    UKW_CONTROL_HEADER header;
    OVERLAPPED overlapped;
    memset(&overlapped, 0, sizeof(overlapped));
    overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (overlapped.hEvent == NULL) {
        printf("Failed to create event for asynchronous request.\n");
        return;
    }

    // send control request "Get Protocol" (51) -- gets version of AAP supported by device (if any)
    unsigned char ioBuffer[2];
    DWORD flags = UKW_TF_IN_TRANSFER;
    header.bmRequestType = 0xC0;
    header.bRequest = 0x33;
    header.wValue = 0x0000;
    header.wIndex = 0x0000;
    header.wLength = 0x0002;
    // Now perform the request
    DWORD transferred = -1;
    BOOL status = UkwIssueControlTransfer(device, flags, &header,
                                          ioBuffer, 2,
                                          &transferred,
                                          &overlapped);
    if (!waitForTransferCompletion(status, device, overlapped, transferred, 2))
        goto out;
    DWORD protocolVersion = (ioBuffer[1] << 8) | ioBuffer[0];
    if (protocolVersion != 1) {
        printf("Device does not support the required Android Accessory Protocol version (supports %d)\n",
               protocolVersion);
        goto out;
    }
    printf("Device supports protocol version: %d\n", protocolVersion);
    // Send the identity strings
    char* identityStrings[] = {
        "RealVNC", // Manufacturer
        "AAPTest", // Model name
        "RealVNC AAP Bearer", // Description
        "0.1", // Version
        "http://www.realvnc.com", // URI
        "0123456789", // Device serial 'number'
    };
    flags = UKW_TF_OUT_TRANSFER;
    header.bmRequestType = 0x40;
    header.bRequest = 0x34;
    header.wValue = 0x0000;
    for(DWORD i = 0; i < (sizeof(identityStrings) / sizeof(char*)) ; ++i) {
        DWORD length = strlen(identityStrings[i]);
        header.wIndex = static_cast<UINT16>(i);
        header.wLength =  static_cast<UINT16>(length);
        status = UkwIssueControlTransfer(device, flags, &header,
                                         identityStrings[i], length,
                                         &transferred,
                                         &overlapped);
        if (!waitForTransferCompletion(status, device, overlapped, transferred, length))
            goto out;
    }

    // Finally request that the device goes into AAP mode
    printf("Requesting device switches to AAP mode\n");
    flags = UKW_TF_OUT_TRANSFER;
    header.bmRequestType = 0x40;
    header.bRequest = 0x35;
    header.wValue = 0x0000;
    header.wIndex = 0x0000;
    header.wLength = 0x0000;
    status = UkwIssueControlTransfer(device, flags, &header,
                                     NULL, 0,
                                     &transferred,
                                     &overlapped);
    if (!waitForTransferCompletion(status, device, overlapped, transferred, 0))
        goto out;
out:
    CloseHandle(overlapped.hEvent);
    return;
}
Exemplo n.º 4
0
static void sendControlRequest(char line[])
{
    // Parse the device index
    DWORD devIdx = 0;
    line = parseNumber(line, devIdx);
    if (!line) {
        printf("Please provide a decimal device number following the command\n");
        return;
    }
    if (devIdx >= gDeviceListSize || devIdx < 0) {
        printf("Invalid device index '%d' provided\n", devIdx);
        return;
    }

    // Parse the option async parameter
    BOOL async;
    DWORD asyncval;
    line = parseNumber(line, asyncval);
    if (line && asyncval != 0) {
        printf("Performing control request asynchronously.\n");
        async = TRUE;
    } else {
        printf("Performing control request synchronously.\n");
        async = FALSE;
    }

    // Input validated so form the request
    UKW_DEVICE device = gDeviceList[devIdx];
    UKW_CONTROL_HEADER header;
    OVERLAPPED overlapped;
    if (async) {
        memset(&overlapped, 0, sizeof(overlapped));
        overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
        if (overlapped.hEvent == NULL) {
            printf("Failed to create event for asynchronous request.\n");
            return;
        }
    }
    DWORD flags = UKW_TF_OUT_TRANSFER;
    header.bmRequestType = 0x40;
    header.bRequest = 0xF0;
    header.wValue = 0x0001;
    header.wIndex = 0x0000;
    header.wLength = 0x0000;
    // Now perform the request
    DWORD transferred = -1;
    BOOL status = UkwIssueControlTransfer(device, flags, &header,
                                          NULL, 0,
                                          &transferred,
                                          async ? &overlapped : NULL);
    if (!status) {
        printf("Control transfer failed with %d.\n", GetLastError());
        return;
    }
    if (async) {
        if (!waitForOverlapped(overlapped)) {
            // Attempt to cancel it
            if (!UkwCancelTransfer(device, &overlapped, 0)) {
                printf("Attempt to cancel timed out transfer failed with %d\n", GetLastError());
                goto out;
            }
            printf("Cancelled transfer due to timeout\n");
            if (!waitForOverlapped(overlapped)) {
                printf("Timeout out waiting for cancel to complete\n");
                goto out;
            }
            printf("Transfer cancel completed with: Internal: %d InternalHigh: %d Offset: %d OffsetHigh %d\n",
                   overlapped.Internal, overlapped.InternalHigh,
                   overlapped.Offset, overlapped.OffsetHigh);
            goto out;
        }
        // Check for the overlapped members being as expected
        if (overlapped.Internal != 0 || overlapped.InternalHigh != 0 ||
                overlapped.Offset != 0 || overlapped.OffsetHigh != 0) {
            printf("Overlapped not as expected. Internal: %d InternalHigh: %d Offset: %d OffsetHigh %d\n",
                   overlapped.Internal, overlapped.InternalHigh,
                   overlapped.Offset, overlapped.OffsetHigh);
            goto out;
        }
    }
    if (transferred != 0) {
        printf("Transferred data length not updated, was %d\n", transferred);
    }
out:
    if (async)
        CloseHandle(overlapped.hEvent);
}