Add classes encapsulatinglegacy USB API

Added implementation for endpoints and overlapped I/O support for legacy API support.
This commit is contained in:
vchtchetkine
2009-07-28 12:45:33 -07:00
parent 743b376b36
commit 39164844f1
10 changed files with 1006 additions and 27 deletions

View File

@@ -88,6 +88,7 @@ PRECOMPILED_SOURCEFILE = stdafx.cpp
SOURCES = adb_api.cpp \ SOURCES = adb_api.cpp \
adb_endpoint_object.cpp \ adb_endpoint_object.cpp \
adb_winusb_endpoint_object.cpp \ adb_winusb_endpoint_object.cpp \
adb_legacy_endpoint_object.cpp \
adb_helper_routines.cpp \ adb_helper_routines.cpp \
adb_interface.cpp \ adb_interface.cpp \
adb_winusb_interface.cpp \ adb_winusb_interface.cpp \
@@ -95,6 +96,7 @@ SOURCES = adb_api.cpp \
adb_interface_enum.cpp \ adb_interface_enum.cpp \
adb_io_completion.cpp \ adb_io_completion.cpp \
adb_winusb_io_completion.cpp \ adb_winusb_io_completion.cpp \
adb_legacy_io_completion.cpp \
adb_object_handle.cpp \ adb_object_handle.cpp \
AdbWinApi.cpp \ AdbWinApi.cpp \
AdbWinApi.rc AdbWinApi.rc

View File

@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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_helper_routines.h"
#include "adb_interface_enum.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, bool EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info,
GUID class_id, GUID class_id,
bool exclude_removed, bool exclude_removed,

View File

@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,6 +23,23 @@
#include "adb_api_private_defines.h" #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 /** \brief Given the hardware device information enumerates interfaces for
this device. this device.

View File

@@ -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();
}

View File

@@ -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__

View File

@@ -17,48 +17,308 @@
/** \file /** \file
This file consists of implementation of class AdbLegacyInterfaceObject This file consists of implementation of class AdbLegacyInterfaceObject
that encapsulates an interface on our USB device that is accessible that encapsulates an interface on our USB device that is accessible
via WinUsb API.
*/ */
#include "stdafx.h" #include "stdafx.h"
#include "adb_api_legacy.h"
#include "adb_legacy_interface.h" #include "adb_legacy_interface.h"
#include "adb_endpoint_object.h" #include "adb_legacy_endpoint_object.h"
AdbLegacyInterfaceObject::AdbLegacyInterfaceObject(const wchar_t* interf_name) 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() { AdbLegacyInterfaceObject::~AdbLegacyInterfaceObject() {
} }
ADBAPIHANDLE AdbLegacyInterfaceObject::CreateHandle() { ADBAPIHANDLE AdbLegacyInterfaceObject::CreateHandle() {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); // 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; return NULL;
} }
bool AdbLegacyInterfaceObject::CloseHandle() { // Now, we ensured that our usb device / interface is up and running.
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); // 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; 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, bool AdbLegacyInterfaceObject::GetSerialNumber(void* buffer,
unsigned long* buffer_char_size, unsigned long* buffer_char_size,
bool ansi) { bool ansi) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); if (!IsOpened()) {
SetLastError(ERROR_INVALID_HANDLE);
return false; 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<unsigned long>(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<wchar_t*>(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<int>(str_len),
reinterpret_cast<PSTR>(buffer),
static_cast<int>(*buffer_char_size),
NULL,
NULL);
return (res != 0);
} }
bool AdbLegacyInterfaceObject::GetEndpointInformation( bool AdbLegacyInterfaceObject::GetEndpointInformation(
UCHAR endpoint_index, UCHAR endpoint_index,
AdbEndpointInformation* info) { AdbEndpointInformation* info) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); // Open USB device for this intefface
return false; 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,
&param, 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( ADBAPIHANDLE AdbLegacyInterfaceObject::OpenEndpoint(
UCHAR endpoint_index, UCHAR endpoint_index,
AdbOpenAccessType access_type, AdbOpenAccessType access_type,
AdbOpenSharingMode sharing_mode) { AdbOpenSharingMode sharing_mode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); // 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 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;
} }

View File

@@ -60,15 +60,6 @@ class AdbLegacyInterfaceObject : public AdbInterfaceObject {
*/ */
virtual ADBAPIHANDLE CreateHandle(); 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 // Abstract overrides
// //
@@ -124,6 +115,76 @@ class AdbLegacyInterfaceObject : public AdbInterfaceObject {
virtual ADBAPIHANDLE OpenEndpoint(UCHAR endpoint_index, virtual ADBAPIHANDLE OpenEndpoint(UCHAR endpoint_index,
AdbOpenAccessType access_type, AdbOpenAccessType access_type,
AdbOpenSharingMode sharing_mode); 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__ #endif // ANDROID_USB_API_ADB_LEGACY_INTERFACE_H__

View File

@@ -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;
}

View File

@@ -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<AdbLegacyEndpointObject*>(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__