diff options
Diffstat (limited to 'fastboot/usb_windows.cpp')
-rw-r--r-- | fastboot/usb_windows.cpp | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp new file mode 100644 index 000000000..a09610f5c --- /dev/null +++ b/fastboot/usb_windows.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <windows.h> +#include <winerror.h> +#include <errno.h> +#include <usb100.h> +#include <adb_api.h> +#include <stdio.h> +#include <stdlib.h> + +#include "usb.h" + +//#define TRACE_USB 1 +#if TRACE_USB +#define DBG(x...) fprintf(stderr, x) +#else +#define DBG(x...) +#endif + +#define MAX_USBFS_BULK_SIZE (1024 * 1024) + +/** Structure usb_handle describes our connection to the usb device via + AdbWinApi.dll. This structure is returned from usb_open() routine and + is expected in each subsequent call that is accessing the device. +*/ +struct usb_handle { + /// Handle to USB interface + ADBAPIHANDLE adb_interface; + + /// Handle to USB read pipe (endpoint) + ADBAPIHANDLE adb_read_pipe; + + /// Handle to USB write pipe (endpoint) + ADBAPIHANDLE adb_write_pipe; + + /// Interface name + char* interface_name; +}; + +/// Class ID assigned to the device by androidusb.sys +static const GUID usb_class_id = ANDROID_USB_CLASS_ID; + + +/// Checks if interface (device) matches certain criteria +int recognized_device(usb_handle* handle, ifc_match_func callback); + +/// Opens usb interface (device) by interface (device) name. +usb_handle* do_usb_open(const wchar_t* interface_name); + +/// Writes data to the opened usb handle +int usb_write(usb_handle* handle, const void* data, int len); + +/// Reads data using the opened usb handle +int usb_read(usb_handle *handle, void* data, int len); + +/// Cleans up opened usb handle +void usb_cleanup_handle(usb_handle* handle); + +/// Cleans up (but don't close) opened usb handle +void usb_kick(usb_handle* handle); + +/// Closes opened usb handle +int usb_close(usb_handle* handle); + + +usb_handle* do_usb_open(const wchar_t* interface_name) { + // Allocate our handle + usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle)); + if (NULL == ret) + return NULL; + + // Create interface. + ret->adb_interface = AdbCreateInterfaceByName(interface_name); + + if (NULL == ret->adb_interface) { + free(ret); + errno = GetLastError(); + return NULL; + } + + // Open read pipe (endpoint) + ret->adb_read_pipe = + AdbOpenDefaultBulkReadEndpoint(ret->adb_interface, + AdbOpenAccessTypeReadWrite, + AdbOpenSharingModeReadWrite); + if (NULL != ret->adb_read_pipe) { + // Open write pipe (endpoint) + ret->adb_write_pipe = + AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface, + AdbOpenAccessTypeReadWrite, + AdbOpenSharingModeReadWrite); + if (NULL != ret->adb_write_pipe) { + // Save interface name + unsigned long name_len = 0; + + // First get expected name length + AdbGetInterfaceName(ret->adb_interface, + NULL, + &name_len, + true); + if (0 != name_len) { + ret->interface_name = (char*)malloc(name_len); + + if (NULL != ret->interface_name) { + // Now save the name + if (AdbGetInterfaceName(ret->adb_interface, + ret->interface_name, + &name_len, + true)) { + // We're done at this point + return ret; + } + } else { + SetLastError(ERROR_OUTOFMEMORY); + } + } + } + } + + // Something went wrong. + errno = GetLastError(); + usb_cleanup_handle(ret); + free(ret); + SetLastError(errno); + + return NULL; +} + +int usb_write(usb_handle* handle, const void* data, int len) { + unsigned long time_out = 5000; + unsigned long written = 0; + unsigned count = 0; + int ret; + + DBG("usb_write %d\n", len); + if (NULL != handle) { + // Perform write + while(len > 0) { + int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len; + ret = AdbWriteEndpointSync(handle->adb_write_pipe, + (void*)data, + (unsigned long)xfer, + &written, + time_out); + errno = GetLastError(); + DBG("AdbWriteEndpointSync returned %d, errno: %d\n", ret, errno); + if (ret == 0) { + // assume ERROR_INVALID_HANDLE indicates we are disconnected + if (errno == ERROR_INVALID_HANDLE) + usb_kick(handle); + return -1; + } + + count += written; + len -= written; + data = (const char *)data + written; + + if (len == 0) + return count; + } + } else { + DBG("usb_write NULL handle\n"); + SetLastError(ERROR_INVALID_HANDLE); + } + + DBG("usb_write failed: %d\n", errno); + + return -1; +} + +int usb_read(usb_handle *handle, void* data, int len) { + unsigned long time_out = 0; + unsigned long read = 0; + int ret; + + DBG("usb_read %d\n", len); + if (NULL != handle) { + while (1) { + int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len; + + ret = AdbReadEndpointSync(handle->adb_read_pipe, + (void*)data, + (unsigned long)xfer, + &read, + time_out); + errno = GetLastError(); + DBG("usb_read got: %ld, expected: %d, errno: %d\n", read, xfer, errno); + if (ret) { + return read; + } else { + // assume ERROR_INVALID_HANDLE indicates we are disconnected + if (errno == ERROR_INVALID_HANDLE) + usb_kick(handle); + break; + } + // else we timed out - try again + } + } else { + DBG("usb_read NULL handle\n"); + SetLastError(ERROR_INVALID_HANDLE); + } + + DBG("usb_read failed: %d\n", errno); + + return -1; +} + +void usb_cleanup_handle(usb_handle* handle) { + if (NULL != handle) { + if (NULL != handle->interface_name) + free(handle->interface_name); + if (NULL != handle->adb_write_pipe) + AdbCloseHandle(handle->adb_write_pipe); + if (NULL != handle->adb_read_pipe) + AdbCloseHandle(handle->adb_read_pipe); + if (NULL != handle->adb_interface) + AdbCloseHandle(handle->adb_interface); + + handle->interface_name = NULL; + handle->adb_write_pipe = NULL; + handle->adb_read_pipe = NULL; + handle->adb_interface = NULL; + } +} + +void usb_kick(usb_handle* handle) { + if (NULL != handle) { + usb_cleanup_handle(handle); + } else { + SetLastError(ERROR_INVALID_HANDLE); + errno = ERROR_INVALID_HANDLE; + } +} + +int usb_close(usb_handle* handle) { + DBG("usb_close\n"); + + if (NULL != handle) { + // Cleanup handle + usb_cleanup_handle(handle); + free(handle); + } + + return 0; +} + +int usb_wait_for_disconnect(usb_handle *usb) { + /* TODO: Punt for now */ + return 0; +} + +int recognized_device(usb_handle* handle, ifc_match_func callback) { + struct usb_ifc_info info; + USB_DEVICE_DESCRIPTOR device_desc; + USB_INTERFACE_DESCRIPTOR interf_desc; + + if (NULL == handle) + return 0; + + // Check vendor and product id first + if (!AdbGetUsbDeviceDescriptor(handle->adb_interface, + &device_desc)) { + return 0; + } + + // Then check interface properties + if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface, + &interf_desc)) { + return 0; + } + + // Must have two endpoints + if (2 != interf_desc.bNumEndpoints) { + return 0; + } + + info.dev_vendor = device_desc.idVendor; + info.dev_product = device_desc.idProduct; + info.dev_class = device_desc.bDeviceClass; + info.dev_subclass = device_desc.bDeviceSubClass; + info.dev_protocol = device_desc.bDeviceProtocol; + info.ifc_class = interf_desc.bInterfaceClass; + info.ifc_subclass = interf_desc.bInterfaceSubClass; + info.ifc_protocol = interf_desc.bInterfaceProtocol; + info.writable = 1; + + // read serial number (if there is one) + unsigned long serial_number_len = sizeof(info.serial_number); + if (!AdbGetSerialNumber(handle->adb_interface, info.serial_number, + &serial_number_len, true)) { + info.serial_number[0] = 0; + } + + info.device_path[0] = 0; + + if (callback(&info) == 0) { + return 1; + } + + return 0; +} + +static usb_handle *find_usb_device(ifc_match_func callback) { + usb_handle* handle = NULL; + char entry_buffer[2048]; + char interf_name[2048]; + AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]); + unsigned long entry_buffer_size = sizeof(entry_buffer); + char* copy_name; + + // Enumerate all present and active interfaces. + ADBAPIHANDLE enum_handle = + AdbEnumInterfaces(usb_class_id, true, true, true); + + if (NULL == enum_handle) + return NULL; + + while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) { + // TODO(vchtchetkine): FIXME - temp hack converting wchar_t into char. + // It would be better to change AdbNextInterface so it will return + // interface name as single char string. + const wchar_t* wchar_name = next_interface->device_name; + for(copy_name = interf_name; + L'\0' != *wchar_name; + wchar_name++, copy_name++) { + *copy_name = (char)(*wchar_name); + } + *copy_name = '\0'; + + handle = do_usb_open(next_interface->device_name); + if (NULL != handle) { + // Lets see if this interface (device) belongs to us + if (recognized_device(handle, callback)) { + // found it! + break; + } else { + usb_cleanup_handle(handle); + free(handle); + handle = NULL; + } + } + + entry_buffer_size = sizeof(entry_buffer); + } + + AdbCloseHandle(enum_handle); + return handle; +} + +usb_handle *usb_open(ifc_match_func callback) +{ + return find_usb_device(callback); +} + +// called from fastboot.c +void sleep(int seconds) +{ + Sleep(seconds * 1000); +} |