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; }
static int wince_reset_device( struct libusb_device_handle *handle) { struct wince_device_priv *priv = _device_priv(handle->dev); if (!UkwResetDevice(priv->dev)) { return translate_driver_error(GetLastError()); } return LIBUSB_SUCCESS; }
static int wince_set_interface_altsetting( struct libusb_device_handle *handle, int interface_number, int altsetting) { struct wince_device_priv *priv = _device_priv(handle->dev); if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting)) { return translate_driver_error(GetLastError()); } return LIBUSB_SUCCESS; }
static int wince_claim_interface( struct libusb_device_handle *handle, int interface_number) { struct wince_device_priv *priv = _device_priv(handle->dev); if (!UkwClaimInterface(priv->dev, interface_number)) { return translate_driver_error(GetLastError()); } return LIBUSB_SUCCESS; }
static int wince_get_device_descriptor( struct libusb_device *device, unsigned char *buffer, int *host_endian) { struct wince_device_priv *priv = _device_priv(device); *host_endian = 1; memcpy(buffer, &priv->desc, DEVICE_DESC_LENGTH); return LIBUSB_SUCCESS; }
static int wince_attach_kernel_driver( struct libusb_device_handle *handle, int interface_number) { struct wince_device_priv *priv = _device_priv(handle->dev); if (!UkwAttachKernelDriver(priv->dev, interface_number)) { return translate_driver_error(GetLastError()); } return LIBUSB_SUCCESS; }
static int wince_kernel_driver_active( struct libusb_device_handle *handle, int interface_number) { struct wince_device_priv *priv = _device_priv(handle->dev); BOOL result = FALSE; if (!UkwKernelDriverActive(priv->dev, interface_number, &result)) { return translate_driver_error(GetLastError()); } return result ? 1 : 0; }
static int wince_cancel_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev); struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT)) return translate_driver_error(GetLastError()); return LIBUSB_SUCCESS; }
static int wince_get_configuration( struct libusb_device_handle *handle, int *config) { struct wince_device_priv *priv = _device_priv(handle->dev); UCHAR cv = 0; if (!UkwGetConfig(priv->dev, &cv)) { return translate_driver_error(GetLastError()); } (*config) = cv; return LIBUSB_SUCCESS; }
static int wince_get_active_config_descriptor( struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian) { struct wince_device_priv *priv = _device_priv(device); DWORD actualSize = len; *host_endian = 0; if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize)) { return translate_driver_error(GetLastError()); } return actualSize; }
static int wince_clear_halt( struct libusb_device_handle *handle, unsigned char endpoint) { struct wince_device_priv *priv = _device_priv(handle->dev); if (!UkwClearHaltHost(priv->dev, endpoint)) { return translate_driver_error(GetLastError()); } if (!UkwClearHaltDevice(priv->dev, endpoint)) { return translate_driver_error(GetLastError()); } return LIBUSB_SUCCESS; }
static int wince_release_interface( struct libusb_device_handle *handle, int interface_number) { struct wince_device_priv *priv = _device_priv(handle->dev); if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0)) { return translate_driver_error(GetLastError()); } if (!UkwReleaseInterface(priv->dev, interface_number)) { return translate_driver_error(GetLastError()); } return LIBUSB_SUCCESS; }
static int wince_set_configuration( struct libusb_device_handle *handle, int config) { struct wince_device_priv *priv = _device_priv(handle->dev); // Setting configuration 0 places the device in Address state. // This should correspond to the "unconfigured state" required by // libusb when the specified configuration is -1. UCHAR cv = (config < 0) ? 0 : config; if (!UkwSetConfig(priv->dev, cv)) { return translate_driver_error(GetLastError()); } return LIBUSB_SUCCESS; }
static int wince_get_config_descriptor( struct libusb_device *device, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) { struct wince_device_priv *priv = _device_priv(device); DWORD actualSize = len; *host_endian = 0; if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize)) return translate_driver_error(GetLastError()); return actualSize; }
static int init_device(struct libusb_device *dev, UKW_DEVICE drv_dev, unsigned char bus_addr, unsigned char dev_addr) { struct wince_device_priv *priv = _device_priv(dev); int r = LIBUSB_SUCCESS; dev->bus_number = bus_addr; dev->device_address = dev_addr; priv->dev = drv_dev; if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc))) { r = translate_driver_error(GetLastError()); } return r; }
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 wince_destroy_device( struct libusb_device *dev) { struct wince_device_priv *priv = _device_priv(dev); UkwReleaseDeviceList(driver_handle, &priv->dev, 1); }