From: vchtchetkine Date: Tue, 28 Jul 2009 19:45:33 +0000 (-0700) Subject: Add classes encapsulatinglegacy USB API X-Git-Tag: android-x86-1.6~7^2~18 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=39164844;p=android-x86%2Fdevelopment.git Add classes encapsulatinglegacy USB API Added implementation for endpoints and overlapped I/O support for legacy API support. --- diff --git a/host/windows/usb/api/SOURCES b/host/windows/usb/api/SOURCES index 4b9d3605..f6e66143 100755 --- a/host/windows/usb/api/SOURCES +++ b/host/windows/usb/api/SOURCES @@ -88,6 +88,7 @@ PRECOMPILED_SOURCEFILE = stdafx.cpp SOURCES = adb_api.cpp \ adb_endpoint_object.cpp \ adb_winusb_endpoint_object.cpp \ + adb_legacy_endpoint_object.cpp \ adb_helper_routines.cpp \ adb_interface.cpp \ adb_winusb_interface.cpp \ @@ -95,6 +96,7 @@ SOURCES = adb_api.cpp \ adb_interface_enum.cpp \ adb_io_completion.cpp \ adb_winusb_io_completion.cpp \ + adb_legacy_io_completion.cpp \ adb_object_handle.cpp \ AdbWinApi.cpp \ AdbWinApi.rc diff --git a/host/windows/usb/api/adb_helper_routines.cpp b/host/windows/usb/api/adb_helper_routines.cpp index 9e373808..e45ff91c 100644 --- a/host/windows/usb/api/adb_helper_routines.cpp +++ b/host/windows/usb/api/adb_helper_routines.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,61 @@ #include "adb_helper_routines.h" #include "adb_interface_enum.h" +bool GetSDKComplientParam(AdbOpenAccessType access_type, + AdbOpenSharingMode sharing_mode, + ULONG* desired_access, + ULONG* desired_sharing) { + if (NULL != desired_access) { + switch (access_type) { + case AdbOpenAccessTypeReadWrite: + *desired_access = GENERIC_READ | GENERIC_WRITE; + break; + + case AdbOpenAccessTypeRead: + *desired_access = GENERIC_READ; + break; + + case AdbOpenAccessTypeWrite: + *desired_access = GENERIC_WRITE; + break; + + case AdbOpenAccessTypeQueryInfo: + *desired_access = FILE_READ_ATTRIBUTES | FILE_READ_EA; + break; + + default: + SetLastError(ERROR_INVALID_ACCESS); + return false; + } + } + + if (NULL != desired_sharing) { + switch (sharing_mode) { + case AdbOpenSharingModeReadWrite: + *desired_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + + case AdbOpenSharingModeRead: + *desired_sharing = FILE_SHARE_READ; + break; + + case AdbOpenSharingModeWrite: + *desired_sharing = FILE_SHARE_WRITE; + break; + + case AdbOpenSharingModeExclusive: + *desired_sharing = 0; + break; + + default: + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + } + + return true; +} + bool EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info, GUID class_id, bool exclude_removed, diff --git a/host/windows/usb/api/adb_helper_routines.h b/host/windows/usb/api/adb_helper_routines.h index 907e638b..b6885e47 100644 --- a/host/windows/usb/api/adb_helper_routines.h +++ b/host/windows/usb/api/adb_helper_routines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,23 @@ #include "adb_api_private_defines.h" +/** \brief Converts access type and share mode from our enum into + SDK - complient values. + + @param[in] access_type Enumerated access type + @param[in] sharing_mode Enumerated share mode + @param[out] desired_access Will receive SDK - complient desired access + flags. This parameter can be NULL. + @param[out] desired_sharing Will receive SDK - complient share mode. + This parameter can be NULL. + @return True on success, false on failure, in which case GetLastError() + provides extended information about the error that occurred. +*/ +bool GetSDKComplientParam(AdbOpenAccessType access_type, + AdbOpenSharingMode sharing_mode, + ULONG* desired_access, + ULONG* desired_sharing); + /** \brief Given the hardware device information enumerates interfaces for this device. diff --git a/host/windows/usb/api/adb_legacy_endpoint_object.cpp b/host/windows/usb/api/adb_legacy_endpoint_object.cpp new file mode 100755 index 00000000..2baa53b3 --- /dev/null +++ b/host/windows/usb/api/adb_legacy_endpoint_object.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** \file + This file consists of implementation of class AdbLegacyEndpointObject that + encapsulates a handle opened to an endpoint on our device controlled by + a custom (legacy) USB driver. +*/ + +#include "stdafx.h" +#include "adb_api_legacy.h" +#include "adb_legacy_endpoint_object.h" +#include "adb_legacy_io_completion.h" +#include "adb_helper_routines.h" + +AdbLegacyEndpointObject::AdbLegacyEndpointObject( + AdbLegacyInterfaceObject* parent_interf, + UCHAR endpoint_id, + UCHAR endpoint_index) + : AdbEndpointObject(parent_interf, endpoint_id, endpoint_index), + usb_handle_(INVALID_HANDLE_VALUE) { +} + +AdbLegacyEndpointObject::~AdbLegacyEndpointObject() { + if (INVALID_HANDLE_VALUE != usb_handle_) { + ::CloseHandle(usb_handle_); + } +} + +ADBAPIHANDLE AdbLegacyEndpointObject::CommonAsyncReadWrite( + bool is_read, + void* buffer, + ULONG bytes_to_transfer, + ULONG* bytes_transferred, + HANDLE event_handle, + ULONG time_out) { + if (NULL != bytes_transferred) { + *bytes_transferred = 0; + } + + if (!IsOpened()) { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + bool is_ioctl_write = is_read ? false : (0 != time_out); + + // Create completion i/o object + AdbLegacyIOCompletion* adb_io_completion = NULL; + + try { + adb_io_completion = new AdbLegacyIOCompletion(this, + bytes_to_transfer, + event_handle, + is_ioctl_write); + } catch (... ) { + // We don't expect exceptions other than OOM thrown here. + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + + // Create a handle for it + ADBAPIHANDLE ret = adb_io_completion->CreateHandle(); + ULONG transferred = 0; + if (NULL != ret) { + BOOL res = TRUE; + if (0 == time_out) { + // Go the read / write file way + res = is_read ? ReadFile(usb_handle(), + buffer, + bytes_to_transfer, + &transferred, + adb_io_completion->overlapped()) : + WriteFile(usb_handle(), + buffer, + bytes_to_transfer, + &transferred, + adb_io_completion->overlapped()); + } else { + // Go IOCTL way + AdbBulkTransfer transfer_param; + transfer_param.time_out = time_out; + transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer; + transfer_param.SetWriteBuffer(is_read ? NULL : buffer); + + res = DeviceIoControl(usb_handle(), + is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE, + &transfer_param, sizeof(transfer_param), + is_read ? buffer : adb_io_completion->transferred_bytes_ptr(), + is_read ? bytes_to_transfer : sizeof(ULONG), + &transferred, + adb_io_completion->overlapped()); + } + + if (NULL != bytes_transferred) { + *bytes_transferred = transferred; + } + + ULONG error = GetLastError(); + if (!res && (ERROR_IO_PENDING != error)) { + // I/O failed immediatelly. We need to close i/o completion object + // before we return NULL to the caller. + adb_io_completion->CloseHandle(); + ret = NULL; + SetLastError(error); + } + } + + // Offseting 'new' + adb_io_completion->Release(); + + return ret; +} + +bool AdbLegacyEndpointObject::CommonSyncReadWrite(bool is_read, + void* buffer, + ULONG bytes_to_transfer, + ULONG* bytes_transferred, + ULONG time_out) { + if (NULL != bytes_transferred) { + *bytes_transferred = 0; + } + + if (!IsOpened()) { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + bool is_ioctl_write = is_read ? false : (0 != time_out); + + // This is synchronous I/O. Since we always open I/O items for + // overlapped I/O we're obligated to always provide OVERLAPPED + // structure to read / write routines. Prepare it now. + OVERLAPPED overlapped; + ZeroMemory(&overlapped, sizeof(overlapped)); + + BOOL ret = TRUE; + ULONG ioctl_write_transferred = 0; + if (0 == time_out) { + // Go the read / write file way + ret = is_read ? + ReadFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped) : + WriteFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped); + } else { + // Go IOCTL way + AdbBulkTransfer transfer_param; + transfer_param.time_out = time_out; + transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer; + transfer_param.SetWriteBuffer(is_read ? NULL : buffer); + + ULONG tmp; + ret = DeviceIoControl(usb_handle(), + is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE, + &transfer_param, sizeof(transfer_param), + is_read ? buffer : &ioctl_write_transferred, + is_read ? bytes_to_transfer : sizeof(ULONG), + &tmp, + &overlapped); + } + + // Lets see the result + if (!ret && (ERROR_IO_PENDING != GetLastError())) { + // I/O failed. + return false; + } + + // Lets wait till I/O completes + ULONG transferred = 0; + ret = GetOverlappedResult(usb_handle(), &overlapped, &transferred, TRUE); + if (ret && (NULL != bytes_transferred)) { + *bytes_transferred = is_ioctl_write ? ioctl_write_transferred : + transferred; + } + + return ret ? true : false; +} + +ADBAPIHANDLE AdbLegacyEndpointObject::CreateHandle( + const wchar_t* item_path, + AdbOpenAccessType access_type, + AdbOpenSharingMode share_mode) { + // Convert access / share parameters into CreateFile - compatible + ULONG desired_access; + ULONG desired_sharing; + + if (!GetSDKComplientParam(access_type, share_mode, + &desired_access, &desired_sharing)) { + return NULL; + } + + // Open USB handle + usb_handle_ = CreateFile(item_path, + desired_access, + share_mode, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, // Always overlapped! + NULL); + if (INVALID_HANDLE_VALUE == usb_handle_) { + return NULL; + } + + // Create ADB handle + ADBAPIHANDLE ret = AdbObjectHandle::CreateHandle(); + + if (NULL == ret) { + // If creation of ADB handle failed we have to close USB handle too. + ULONG error = GetLastError(); + ::CloseHandle(usb_handle()); + usb_handle_ = INVALID_HANDLE_VALUE; + SetLastError(error); + } + + return ret; +} + +bool AdbLegacyEndpointObject::CloseHandle() { + if (INVALID_HANDLE_VALUE != usb_handle_) { + ::CloseHandle(usb_handle_); + usb_handle_ = INVALID_HANDLE_VALUE; + } + + return AdbEndpointObject::CloseHandle(); +} diff --git a/host/windows/usb/api/adb_legacy_endpoint_object.h b/host/windows/usb/api/adb_legacy_endpoint_object.h new file mode 100755 index 00000000..a8613d2b --- /dev/null +++ b/host/windows/usb/api/adb_legacy_endpoint_object.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_USB_API_ADB_LEGACY_ENDPOINT_OBJECT_H__ +#define ANDROID_USB_API_ADB_LEGACY_ENDPOINT_OBJECT_H__ +/** \file + This file consists of declaration of class AdbLegacyEndpointObject that + encapsulates a handle opened to an endpoint on our device controlled by + a custom (legacy) USB driver. +*/ + +#include "adb_endpoint_object.h" +#include "adb_legacy_interface.h" + +/** Encapsulates a handle opened to an endpoint on our device controlled by + a custom (legacy) USB driver. +*/ +class AdbLegacyEndpointObject : public AdbEndpointObject { + public: + /** \brief Constructs the object + + @param[in] interface Parent legacy USB interface for this object. + @param[in] endpoint_id Endpoint ID (endpoint address) on the device. + @param[in] endpoint_index Zero-based endpoint index in the interface's + array of endpoints. + */ + AdbLegacyEndpointObject(AdbLegacyInterfaceObject* parent_interf, + UCHAR endpoint_id, + UCHAR endpoint_index); + + protected: + /** \brief Destructs the object. + + We hide destructor in order to prevent ourseves from accidentaly allocating + instances on the stack. If such attemp occur, compiler will error. + */ + virtual ~AdbLegacyEndpointObject(); + + // + // Abstract overrides + // + + protected: + /** \brief Common code for async read / write + + @param[in] is_read Read or write selector. + @param[in,out] buffer Pointer to the buffer for read / write. + @param[in] bytes_to_transfer Number of bytes to be read / written. + @param[out] bytes_transferred Number of bytes read / written. Can be NULL. + @param[in] event_handle Event handle that should be signaled when async I/O + completes. Can be NULL. If it's not NULL this handle will be used to + initialize OVERLAPPED structure for this I/O. + @param[in] time_out A timeout (in milliseconds) required for this I/O to + complete. Zero value in this parameter means that there is no + timeout set for this I/O. + @return A handle to IO completion object or NULL on failure. If NULL is + returned GetLastError() provides extended error information. + */ + virtual ADBAPIHANDLE CommonAsyncReadWrite(bool is_read, + void* buffer, + ULONG bytes_to_transfer, + ULONG* bytes_transferred, + HANDLE event_handle, + ULONG time_out); + + /** \brief Common code for sync read / write + + @param[in] is_read Read or write selector. + @param[in,out] buffer Pointer to the buffer for read / write. + @param[in] bytes_to_transfer Number of bytes to be read / written. + @param[out] bytes_transferred Number of bytes read / written. Can be NULL. + @param[in] time_out A timeout (in milliseconds) required for this I/O to + complete. Zero value in this parameter means that there is no + timeout set for this I/O. + @return true on success, false on failure. If false is returned + GetLastError() provides extended error information. + */ + virtual bool CommonSyncReadWrite(bool is_read, + void* buffer, + ULONG bytes_to_transfer, + ULONG* bytes_transferred, + ULONG time_out); + + // + // Operations + // + + public: + /** \brief Opens endpoint and creates a handle to this object + + @param item_path[in] Path to the endpoint on our USB device. + @param access_type[in] Desired access type. In the current implementation + this parameter has no effect on the way item is opened. It's + always read / write access. + @param sharing_mode[in] Desired share mode. In the current implementation + this parameter has no effect on the way item is opened. It's + always shared for read / write. + @return A handle to this object on success or NULL on an error. + If NULL is returned GetLastError() provides extended error + information. ERROR_GEN_FAILURE is set if an attempt was + made to create already opened object. + */ + virtual ADBAPIHANDLE CreateHandle(const wchar_t* item_path, + AdbOpenAccessType access_type, + AdbOpenSharingMode share_mode); + + + /** \brief This method is called when handle to this object gets closed. + + We override this method in order to close handle to the endpoint opened + in CreateHandle method of this class. + @return true on success or false if object is already closed. If + false is returned GetLastError() provides extended error + information. + */ + virtual bool CloseHandle(); + + public: + /// Gets handle to the endpoint opened on our USB device. + HANDLE usb_handle() const { + return usb_handle_; + } + + protected: + /// Handle to the endpoint opened on our USB device. + HANDLE usb_handle_; +}; + +#endif // ANDROID_USB_API_ADB_LEGACY_ENDPOINT_OBJECT_H__ diff --git a/host/windows/usb/api/adb_legacy_interface.cpp b/host/windows/usb/api/adb_legacy_interface.cpp index 95c750e6..9eab9bd5 100755 --- a/host/windows/usb/api/adb_legacy_interface.cpp +++ b/host/windows/usb/api/adb_legacy_interface.cpp @@ -17,48 +17,308 @@ /** \file This file consists of implementation of class AdbLegacyInterfaceObject that encapsulates an interface on our USB device that is accessible - via WinUsb API. */ #include "stdafx.h" +#include "adb_api_legacy.h" #include "adb_legacy_interface.h" -#include "adb_endpoint_object.h" +#include "adb_legacy_endpoint_object.h" AdbLegacyInterfaceObject::AdbLegacyInterfaceObject(const wchar_t* interf_name) - : AdbInterfaceObject(interf_name) { + : AdbInterfaceObject(interf_name), + def_read_endpoint_(0xFF), + read_endpoint_id_(0xFF), + def_write_endpoint_(0xFF), + write_endpoint_id_(0xFF) { } AdbLegacyInterfaceObject::~AdbLegacyInterfaceObject() { } ADBAPIHANDLE AdbLegacyInterfaceObject::CreateHandle() { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; -} + // Open USB device for this intefface + HANDLE usb_device_handle = CreateFile(interface_name().c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (INVALID_HANDLE_VALUE == usb_device_handle) { + return NULL; + } + + // Now, we ensured that our usb device / interface is up and running. + // Lets collect device, interface and pipe information + bool ok = true; + if (!CacheUsbDeviceDescriptor(usb_device_handle) || + !CacheUsbConfigurationDescriptor(usb_device_handle) || + !CacheUsbInterfaceDescriptor(usb_device_handle)) { + ok = false; + } + + // Preserve error accross handle close + ULONG error = ok ? NO_ERROR : GetLastError(); + + ::CloseHandle(usb_device_handle); + + if (NO_ERROR != error) { + SetLastError(error); + } + + if (!ok) { + return false; + } -bool AdbLegacyInterfaceObject::CloseHandle() { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; + // Save indexes and IDs for bulk read / write endpoints. We will use them to + // convert ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX and + // ADB_QUERY_BULK_READ_ENDPOINT_INDEX into actual endpoint indexes and IDs. + for (UCHAR endpoint = 0; endpoint < usb_interface_descriptor_.bNumEndpoints; + endpoint++) { + // Get endpoint information + AdbEndpointInformation pipe_info; + if (!GetEndpointInformation(endpoint, &pipe_info)) { + return false; + } + + if (AdbEndpointTypeBulk == pipe_info.endpoint_type) { + // This is a bulk endpoint. Cache its index and ID. + if (0 != (pipe_info.endpoint_address & USB_ENDPOINT_DIRECTION_MASK)) { + // Use this endpoint as default bulk read endpoint + ATLASSERT(0xFF == def_read_endpoint_); + def_read_endpoint_ = endpoint; + read_endpoint_id_ = pipe_info.endpoint_address; + } else { + // Use this endpoint as default bulk write endpoint + ATLASSERT(0xFF == def_write_endpoint_); + def_write_endpoint_ = endpoint; + write_endpoint_id_ = pipe_info.endpoint_address; + } + } + } + + return AdbObjectHandle::CreateHandle(); } bool AdbLegacyInterfaceObject::GetSerialNumber(void* buffer, unsigned long* buffer_char_size, bool ansi) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; + if (!IsOpened()) { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // Open USB device for this intefface + HANDLE usb_device_handle = CreateFile(interface_name().c_str(), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (INVALID_HANDLE_VALUE == usb_device_handle) { + return NULL; + } + + WCHAR serial_number[512]; + + // Send IOCTL + DWORD ret_bytes = 0; + BOOL ret = DeviceIoControl(usb_device_handle, + ADB_IOCTL_GET_SERIAL_NUMBER, + NULL, 0, + serial_number, sizeof(serial_number), + &ret_bytes, + NULL); + + // Preserve error accross CloseHandle + ULONG error = ret ? NO_ERROR : GetLastError(); + + ::CloseHandle(usb_device_handle); + + if (NO_ERROR != error) { + SetLastError(error); + return false; + } + + unsigned long str_len = + static_cast(wcslen(serial_number) + 1); + + if ((NULL == buffer) || (*buffer_char_size < str_len)) { + *buffer_char_size = str_len; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return false; + } + + if (!ansi) { + // If user asked for wide char name just return it + wcscpy(reinterpret_cast(buffer), serial_number); + return true; + } + + // We need to convert name from wide char to ansi string + int res = WideCharToMultiByte(CP_ACP, + 0, + serial_number, + static_cast(str_len), + reinterpret_cast(buffer), + static_cast(*buffer_char_size), + NULL, + NULL); + return (res != 0); } bool AdbLegacyInterfaceObject::GetEndpointInformation( UCHAR endpoint_index, AdbEndpointInformation* info) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; + // Open USB device for this intefface + HANDLE usb_device_handle = CreateFile(interface_name().c_str(), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (INVALID_HANDLE_VALUE == usb_device_handle) { + return NULL; + } + + // Init ICTL param + AdbQueryEndpointInformation param; + param.endpoint_index = endpoint_index; + + // Send IOCTL + DWORD ret_bytes = 0; + BOOL ret = DeviceIoControl(usb_device_handle, + ADB_IOCTL_GET_ENDPOINT_INFORMATION, + ¶m, sizeof(param), + info, sizeof(AdbEndpointInformation), + &ret_bytes, + NULL); + ATLASSERT(!ret || (sizeof(AdbEndpointInformation) == ret_bytes)); + + // Preserve error accross CloseHandle + ULONG error = ret ? NO_ERROR : GetLastError(); + + ::CloseHandle(usb_device_handle); + + if (NO_ERROR != error) { + SetLastError(error); + } + + return ret ? true : false; } ADBAPIHANDLE AdbLegacyInterfaceObject::OpenEndpoint( UCHAR endpoint_index, AdbOpenAccessType access_type, AdbOpenSharingMode sharing_mode) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + // Convert index into name and ID. + std::wstring endpoint_name; + UCHAR endpoint_id; + + try { + if ((ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) || + (def_read_endpoint_ == endpoint_index)) { + endpoint_name = DEVICE_BULK_READ_PIPE_NAME; + endpoint_id = read_endpoint_id_; + endpoint_index = def_read_endpoint_; + } else if ((ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) || + (def_write_endpoint_ == endpoint_index)) { + endpoint_name = DEVICE_BULK_WRITE_PIPE_NAME; + endpoint_id = write_endpoint_id_; + endpoint_index = def_write_endpoint_; + } else { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + } catch (...) { + // We don't expect exceptions other than OOM thrown here. + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + + return OpenEndpoint(endpoint_name.c_str(), endpoint_id, endpoint_index, + access_type, sharing_mode); +} + +ADBAPIHANDLE AdbLegacyInterfaceObject::OpenEndpoint( + const wchar_t* endpoint_name, + UCHAR endpoint_id, + UCHAR endpoint_index, + AdbOpenAccessType access_type, + AdbOpenSharingMode sharing_mode) { + if (!IsOpened()) { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + AdbLegacyEndpointObject* adb_endpoint = NULL; + + try { + adb_endpoint = + new AdbLegacyEndpointObject(this, endpoint_id, endpoint_index); + } catch (...) { + // We don't expect exceptions other than OOM thrown here. + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + + // Build full path to the object + std::wstring endpoint_path = interface_name(); + endpoint_path += L"\\"; + endpoint_path += endpoint_name; + + ADBAPIHANDLE ret = adb_endpoint->CreateHandle(endpoint_path.c_str(), + access_type, + sharing_mode); + + adb_endpoint->Release(); + + return ret; +} + +bool AdbLegacyInterfaceObject::CacheUsbDeviceDescriptor( + HANDLE usb_device_handle) { + DWORD ret_bytes = 0; + BOOL ret = DeviceIoControl(usb_device_handle, + ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR, + NULL, 0, + &usb_device_descriptor_, + sizeof(usb_device_descriptor_), + &ret_bytes, + NULL); + ATLASSERT(!ret || (sizeof(USB_DEVICE_DESCRIPTOR) == ret_bytes)); + + return ret ? true : false; +} + +bool AdbLegacyInterfaceObject::CacheUsbConfigurationDescriptor( + HANDLE usb_device_handle) { + DWORD ret_bytes = 0; + BOOL ret = DeviceIoControl(usb_device_handle, + ADB_IOCTL_GET_USB_CONFIGURATION_DESCRIPTOR, + NULL, 0, + &usb_config_descriptor_, + sizeof(usb_config_descriptor_), + &ret_bytes, + NULL); + ATLASSERT(!ret || (sizeof(USB_CONFIGURATION_DESCRIPTOR) == ret_bytes)); + + return ret ? true : false; +} + +bool AdbLegacyInterfaceObject::CacheUsbInterfaceDescriptor( + HANDLE usb_device_handle) { + DWORD ret_bytes = 0; + BOOL ret = DeviceIoControl(usb_device_handle, + ADB_IOCTL_GET_USB_INTERFACE_DESCRIPTOR, + NULL, 0, + &usb_interface_descriptor_, + sizeof(usb_interface_descriptor_), + &ret_bytes, + NULL); + ATLASSERT(!ret || (sizeof(USB_INTERFACE_DESCRIPTOR) == ret_bytes)); + + return ret ? true : false; } diff --git a/host/windows/usb/api/adb_legacy_interface.h b/host/windows/usb/api/adb_legacy_interface.h index 6d4b0e84..8dd0b22a 100755 --- a/host/windows/usb/api/adb_legacy_interface.h +++ b/host/windows/usb/api/adb_legacy_interface.h @@ -60,15 +60,6 @@ class AdbLegacyInterfaceObject : public AdbInterfaceObject { */ virtual ADBAPIHANDLE CreateHandle(); - /** \brief This method is called when handle to this object gets closed. - - In this call object is deleted from the AdbObjectHandleMap. - @return true on success or false if object is already closed. If - false is returned GetLastError() provides extended error - information. - */ - virtual bool CloseHandle(); - // // Abstract overrides // @@ -124,6 +115,76 @@ class AdbLegacyInterfaceObject : public AdbInterfaceObject { virtual ADBAPIHANDLE OpenEndpoint(UCHAR endpoint_index, AdbOpenAccessType access_type, AdbOpenSharingMode sharing_mode); + + // + // Internal operations + // + + protected: + /** \brief Opens an endpoint on this interface. + + @param[in] endpoint_name Endpoint file name. + @param[in] endpoint_id Endpoint (pipe) address on the device. + @param[in] endpoint_index Zero-based endpoint index. + @param[in] access_type Desired access type. In the current implementation + this parameter has no effect on the way endpoint is opened. It's + always read / write access. + @param[in] sharing_mode Desired share mode. In the current implementation + this parameter has no effect on the way endpoint is opened. It's + always shared for read / write. + @return Handle to the opened endpoint object or NULL on failure. + If NULL is returned GetLastError() provides extended information + about the error that occurred. + */ + ADBAPIHANDLE OpenEndpoint(const wchar_t* endpoint_name, + UCHAR endpoint_id, + UCHAR endpoint_index, + AdbOpenAccessType access_type, + AdbOpenSharingMode sharing_mode); + + /** \brief Caches device descriptor for the USB device associated with + this interface. + + This method is called from CreateHandle method to cache some interface + information. + @param[in] usb_device_handle Handle to USB device. + @return 'true' on success, 'false' on failure. If 'false' is returned + GetLastError() provides extended error information. + */ + bool CacheUsbDeviceDescriptor(HANDLE usb_device_handle); + + /** \brief Caches descriptor for the selected USB device configuration. + + This method is called from CreateHandle method to cache some interface + information. + @param[in] usb_device_handle Handle to USB device. + @return 'true' on success, 'false' on failure. If 'false' is returned + GetLastError() provides extended error information. + */ + bool CacheUsbConfigurationDescriptor(HANDLE usb_device_handle); + + /** \brief Caches descriptor for this interface. + + This method is called from CreateHandle method to cache some interface + information. + @param[in] usb_device_handle Handle to USB device. + @return 'true' on success, 'false' on failure. If 'false' is returned + GetLastError() provides extended error information. + */ + bool CacheUsbInterfaceDescriptor(HANDLE usb_device_handle); + + protected: + /// Index for the default bulk read endpoint + UCHAR def_read_endpoint_; + + /// ID for the default bulk read endpoint + UCHAR read_endpoint_id_; + + /// Index for the default bulk write endpoint + UCHAR def_write_endpoint_; + + /// ID for the default bulk write endpoint + UCHAR write_endpoint_id_; }; #endif // ANDROID_USB_API_ADB_LEGACY_INTERFACE_H__ diff --git a/host/windows/usb/api/adb_legacy_io_completion.cpp b/host/windows/usb/api/adb_legacy_io_completion.cpp new file mode 100755 index 00000000..e3d1498f --- /dev/null +++ b/host/windows/usb/api/adb_legacy_io_completion.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** \file + This file consists of implementation of class AdbLegacyIOCompletion that + encapsulates a wrapper around OVERLAPPED Win32 structure returned from + asynchronous I/O requests issued via legacy USB API. +*/ + +#include "stdafx.h" +#include "adb_legacy_io_completion.h" + +AdbLegacyIOCompletion::AdbLegacyIOCompletion( + AdbLegacyEndpointObject* parent_io_obj, + ULONG expected_trans_size, + HANDLE event_hndl, + bool is_write_ctl) + : AdbIOCompletion(parent_io_obj, expected_trans_size, event_hndl), + transferred_bytes_(0), + is_write_ioctl_(is_write_ctl) { +} + +AdbLegacyIOCompletion::~AdbLegacyIOCompletion() { +} + +bool AdbLegacyIOCompletion::GetOvelappedIoResult(LPOVERLAPPED ovl_data, + ULONG* bytes_transferred, + bool wait) { + if (NULL != bytes_transferred) { + *bytes_transferred = 0; + } + + if (!IsOpened()) { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + ULONG transfer; + bool ret = GetOverlappedResult(parent_legacy_io_object()->usb_handle(), + overlapped(), + &transfer, + wait) ? true : + false; + + // TODO: This is bizzare but I've seen it happening + // that GetOverlappedResult with wait set to true returns "prematurely", + // with wrong transferred bytes value and GetLastError reporting + // ERROR_IO_PENDING. So, lets give it an up to a 20 ms loop! + ULONG error = GetLastError(); + + if (wait && ret && (0 == transfer) && (0 != expected_transfer_size_) && + ((ERROR_IO_INCOMPLETE == error) || (ERROR_IO_PENDING == error))) { + for (int trying = 0; trying < 10; trying++) { + Sleep(2); + ret = GetOverlappedResult(parent_legacy_io_object()->usb_handle(), + overlapped(), + &transfer, + wait) ? true : + false; + error = GetLastError(); + if (!ret || (0 != transfer) || + ((ERROR_IO_INCOMPLETE != error) && (ERROR_IO_PENDING != error))) { + break; + } + } + } + + if (NULL != ovl_data) { + CopyMemory(ovl_data, overlapped(), sizeof(OVERLAPPED)); + } + + if (NULL != bytes_transferred) { + *bytes_transferred = is_write_ioctl() ? transferred_bytes_ : transfer; + } + + return ret; +} diff --git a/host/windows/usb/api/adb_legacy_io_completion.h b/host/windows/usb/api/adb_legacy_io_completion.h new file mode 100755 index 00000000..743219e4 --- /dev/null +++ b/host/windows/usb/api/adb_legacy_io_completion.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_USB_API_ADB_LEGACY_IO_COMPLETION_H__ +#define ANDROID_USB_API_ADB_LEGACY_IO_COMPLETION_H__ +/** \file + This file consists of declaration of class AdbLegacyIOCompletion that + encapsulates a wrapper around OVERLAPPED Win32 structure returned from + asynchronous I/O requests issued via legacy USB API. +*/ + +#include "adb_io_completion.h" +#include "adb_legacy_endpoint_object.h" + +/** \brief Encapsulates a wrapper around OVERLAPPED Win32 structure returned + from asynchronous I/O requests issued via legacy USB API. + + A handle to this object is returned to the caller of each successful + asynchronous I/O request. Just like all other handles this handle + must be closed after it's no longer needed. +*/ +class AdbLegacyIOCompletion : public AdbIOCompletion { + public: + /** \brief Constructs the object. + + @param[in] parent_io_obj Parent legacy endpoint that created this + instance. + @param[in] expected_trans_size Number of bytes expected to be transferred + with the I/O. + @param[in] event_hndl Event handle that should be signaled when I/O + completes. Can be NULL. If it's not NULL this handle will be + used to initialize OVERLAPPED structure for this object. + @param[in] is_write_ctl Flag indicating whether or not this completion + object is created for ADB_IOCTL_BULK_WRITE I/O. + */ + AdbLegacyIOCompletion(AdbLegacyEndpointObject* parent_io_obj, + ULONG expected_trans_size, + HANDLE event_hndl, + bool is_write_ctl); + + protected: + /** \brief Destructs the object. + + We hide destructor in order to prevent ourseves from accidentaly allocating + instances on the stack. If such attemp occur, compiler will error. + */ + virtual ~AdbLegacyIOCompletion(); + + // + // Abstract overrides + // + + public: + /** \brief Gets overlapped I/O result + + This method uses GetOverlappedResult to get results of the overlapped I/O + operation. + @param[out] ovl_data Buffer for the copy of this object's OVERLAPPED + structure. Can be NULL. + @param[out] bytes_transferred Pointer to a variable that receives the + number of bytes that were actually transferred by a read or write + operation. See SDK doc on GetOvelappedResult for more information. + Unlike regular GetOvelappedResult call this parameter can be NULL. + @param[in] wait If this parameter is true, the method does not return + until the operation has been completed. If this parameter is false + and the operation is still pending, the method returns false and + the GetLastError function returns ERROR_IO_INCOMPLETE. + @return true if I/O has been completed or false on failure or if request + is not yet completed. If false is returned GetLastError() provides + extended error information. If GetLastError returns + ERROR_IO_INCOMPLETE it means that I/O is not yet completed. + */ + virtual bool GetOvelappedIoResult(LPOVERLAPPED ovl_data, + ULONG* bytes_transferred, + bool wait); + + public: + /// Gets parent legacy endpoint. + AdbLegacyEndpointObject* parent_legacy_io_object() const { + return reinterpret_cast(parent_io_object()); + } + + /// Gets write IOCTL flag. + bool is_write_ioctl() const { + return is_write_ioctl_; + } + + /// Gets address for ADB_IOCTL_BULK_WRITE output buffer. + ULONG* transferred_bytes_ptr() { + ATLASSERT(is_write_ioctl()); + return &transferred_bytes_; + } + + protected: + /// Recepient for number of transferred bytes in write IOCTL. + ULONG transferred_bytes_; + + /// Write IOCTL flag. + bool is_write_ioctl_; +}; + +#endif // ANDROID_USB_API_ADB_LEGACY_IO_COMPLETION_H__ diff --git a/host/windows/usb/api/adb_winusb_interface.cpp b/host/windows/usb/api/adb_winusb_interface.cpp index 00e575d3..d09c1cbe 100755 --- a/host/windows/usb/api/adb_winusb_interface.cpp +++ b/host/windows/usb/api/adb_winusb_interface.cpp @@ -305,7 +305,7 @@ ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint( } ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint(UCHAR endpoint_id, - UCHAR endpoint_index) { + UCHAR endpoint_index) { if (!IsOpened()) { SetLastError(ERROR_INVALID_HANDLE); return false;