/* | |
* Copyright (C) 2006 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 AdbInterfaceObject that | |
encapsulates an interface on our USB device. | |
*/ | |
#include "stdafx.h" | |
#include "adb_interface.h" | |
#include "adb_endpoint_object.h" | |
AdbInterfaceObject::AdbInterfaceObject(const wchar_t* interf_name) | |
: AdbObjectHandle(AdbObjectTypeInterface), | |
interface_name_(interf_name), | |
usb_device_handle_(INVALID_HANDLE_VALUE), | |
winusb_handle_(NULL), | |
interface_number_(0xFF), | |
def_read_endpoint_(0xFF), | |
read_endpoint_id_(0xFF), | |
def_write_endpoint_(0xFF), | |
write_endpoint_id_(0xFF) { | |
ATLASSERT(NULL != interf_name); | |
} | |
AdbInterfaceObject::~AdbInterfaceObject() { | |
ATLASSERT(NULL == winusb_handle_); | |
ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_); | |
} | |
ADBAPIHANDLE AdbInterfaceObject::CreateHandle() { | |
// Open USB device for this inteface Note that WinUsb API | |
// requires the handle to be opened for overlapped I/O. | |
usb_device_handle_ = CreateFile(interface_name().c_str(), | |
GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, OPEN_EXISTING, | |
FILE_FLAG_OVERLAPPED, NULL); | |
if (INVALID_HANDLE_VALUE == usb_device_handle_) | |
return NULL; | |
// Initialize WinUSB API for this interface | |
if (!WinUsb_Initialize(usb_device_handle_, &winusb_handle_)) | |
return NULL; | |
// Cache current interface number that will be used in | |
// WinUsb_Xxx calls performed on this interface. | |
if (!WinUsb_GetCurrentAlternateSetting(winusb_handle(), &interface_number_)) | |
return false; | |
// Cache interface properties | |
unsigned long bytes_written; | |
// Cache USB device descriptor | |
if (!WinUsb_GetDescriptor(winusb_handle(), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, | |
reinterpret_cast<PUCHAR>(&usb_device_descriptor_), | |
sizeof(usb_device_descriptor_), &bytes_written)) { | |
return false; | |
} | |
// Cache USB configuration descriptor | |
if (!WinUsb_GetDescriptor(winusb_handle(), USB_CONFIGURATION_DESCRIPTOR_TYPE, | |
0, 0, | |
reinterpret_cast<PUCHAR>(&usb_config_descriptor_), | |
sizeof(usb_config_descriptor_), &bytes_written)) { | |
return false; | |
} | |
// Cache USB interface descriptor | |
if (!WinUsb_QueryInterfaceSettings(winusb_handle(), interface_number(), | |
&usb_interface_descriptor_)) { | |
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 | |
WINUSB_PIPE_INFORMATION pipe_info; | |
if (!WinUsb_QueryPipe(winusb_handle(), interface_number(), endpoint, | |
&pipe_info)) { | |
return false; | |
} | |
if (UsbdPipeTypeBulk == pipe_info.PipeType) { | |
// This is a bulk endpoint. Cache its index and ID. | |
if (0 != (pipe_info.PipeId & 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.PipeId; | |
} else { | |
// Use this endpoint as default bulk write endpoint | |
ATLASSERT(0xFF == def_write_endpoint_); | |
def_write_endpoint_ = endpoint; | |
write_endpoint_id_ = pipe_info.PipeId; | |
} | |
} | |
} | |
return AdbObjectHandle::CreateHandle(); | |
} | |
bool AdbInterfaceObject::CloseHandle() { | |
if (NULL != winusb_handle_) { | |
WinUsb_Free(winusb_handle_); | |
winusb_handle_ = NULL; | |
} | |
if (INVALID_HANDLE_VALUE != usb_device_handle_) { | |
::CloseHandle(usb_device_handle_); | |
usb_device_handle_ = INVALID_HANDLE_VALUE; | |
} | |
return AdbObjectHandle::CloseHandle(); | |
} | |
bool AdbInterfaceObject::GetInterfaceName(void* buffer, | |
unsigned long* buffer_char_size, | |
bool ansi) { | |
if (NULL == buffer_char_size) { | |
SetLastError(ERROR_INVALID_PARAMETER); | |
return false; | |
} | |
// Lets see if buffer is big enough | |
ULONG name_len = static_cast<ULONG>(interface_name_.length() + 1); | |
if ((NULL == buffer) || (*buffer_char_size < name_len)) { | |
*buffer_char_size = name_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), interface_name().c_str()); | |
return true; | |
} | |
// We need to convert name from wide char to ansi string | |
int res = WideCharToMultiByte(CP_ACP, | |
0, | |
interface_name().c_str(), | |
static_cast<int>(name_len), | |
reinterpret_cast<PSTR>(buffer), | |
static_cast<int>(*buffer_char_size), | |
NULL, | |
NULL); | |
return (res != 0); | |
} | |
bool AdbInterfaceObject::GetSerialNumber(void* buffer, | |
unsigned long* buffer_char_size, | |
bool ansi) { | |
if (!IsOpened()) { | |
SetLastError(ERROR_INVALID_HANDLE); | |
return false; | |
} | |
if (NULL == buffer_char_size) { | |
SetLastError(ERROR_INVALID_PARAMETER); | |
return false; | |
} | |
// Calculate serial number string size. Note that WinUsb_GetDescriptor | |
// API will not return number of bytes needed to store serial number | |
// string. So we will have to start with a reasonably large preallocated | |
// buffer and then loop through WinUsb_GetDescriptor calls, doubling up | |
// string buffer size every time ERROR_INSUFFICIENT_BUFFER is returned. | |
union { | |
// Preallocate reasonably sized buffer on the stack. | |
char small_buffer[64]; | |
USB_STRING_DESCRIPTOR initial_ser_num; | |
}; | |
USB_STRING_DESCRIPTOR* ser_num = &initial_ser_num; | |
// Buffer byte size | |
unsigned long ser_num_size = sizeof(small_buffer); | |
// After successful call to WinUsb_GetDescriptor will contain serial | |
// number descriptor size. | |
unsigned long bytes_written; | |
while (!WinUsb_GetDescriptor(winusb_handle(), USB_STRING_DESCRIPTOR_TYPE, | |
usb_device_descriptor_.iSerialNumber, | |
0x0409, // English (US) | |
reinterpret_cast<PUCHAR>(ser_num), | |
ser_num_size, &bytes_written)) { | |
// Any error other than ERROR_INSUFFICIENT_BUFFER is terminal here. | |
if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) { | |
if (ser_num != &initial_ser_num) | |
delete[] reinterpret_cast<char*>(ser_num); | |
return false; | |
} | |
// Double up buffer size and reallocate string buffer | |
ser_num_size *= 2; | |
if (ser_num != &initial_ser_num) | |
delete[] reinterpret_cast<char*>(ser_num); | |
try { | |
ser_num = | |
reinterpret_cast<USB_STRING_DESCRIPTOR*>(new char[ser_num_size]); | |
} catch (...) { | |
SetLastError(ERROR_OUTOFMEMORY); | |
return false; | |
} | |
} | |
// Serial number string length | |
unsigned long str_len = (ser_num->bLength - | |
FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)) / | |
sizeof(wchar_t); | |
// Lets see if requested buffer is big enough to fit the string | |
if ((NULL == buffer) || (*buffer_char_size < (str_len + 1))) { | |
// Requested buffer is too small. | |
if (ser_num != &initial_ser_num) | |
delete[] reinterpret_cast<char*>(ser_num); | |
*buffer_char_size = str_len + 1; | |
SetLastError(ERROR_INSUFFICIENT_BUFFER); | |
return false; | |
} | |
bool ret = true; | |
if (ansi) { | |
// We need to convert name from wide char to ansi string | |
if (0 != WideCharToMultiByte(CP_ACP, 0, ser_num->bString, | |
static_cast<int>(str_len), | |
reinterpret_cast<PSTR>(buffer), | |
static_cast<int>(*buffer_char_size), | |
NULL, NULL)) { | |
// Zero-terminate output string. | |
reinterpret_cast<char*>(buffer)[str_len] = '\0'; | |
} else { | |
ret = false; | |
} | |
} else { | |
// For wide char output just copy string buffer, | |
// and zero-terminate output string. | |
CopyMemory(buffer, ser_num->bString, bytes_written); | |
reinterpret_cast<wchar_t*>(buffer)[str_len] = L'\0'; | |
} | |
if (ser_num != &initial_ser_num) | |
delete[] reinterpret_cast<char*>(ser_num); | |
return ret; | |
} | |
bool AdbInterfaceObject::GetUsbDeviceDescriptor(USB_DEVICE_DESCRIPTOR* desc) { | |
if (!IsOpened()) { | |
SetLastError(ERROR_INVALID_HANDLE); | |
return false; | |
} | |
if (NULL == desc) { | |
SetLastError(ERROR_INVALID_PARAMETER); | |
return false; | |
} | |
CopyMemory(desc, usb_device_descriptor(), sizeof(USB_DEVICE_DESCRIPTOR)); | |
return true; | |
} | |
bool AdbInterfaceObject::GetUsbConfigurationDescriptor( | |
USB_CONFIGURATION_DESCRIPTOR* desc) { | |
if (!IsOpened()) { | |
SetLastError(ERROR_INVALID_HANDLE); | |
return false; | |
} | |
if (NULL == desc) { | |
SetLastError(ERROR_INVALID_PARAMETER); | |
return false; | |
} | |
CopyMemory(desc, usb_config_descriptor(), | |
sizeof(USB_CONFIGURATION_DESCRIPTOR)); | |
return true; | |
} | |
bool AdbInterfaceObject::GetUsbInterfaceDescriptor( | |
USB_INTERFACE_DESCRIPTOR* desc) { | |
if (!IsOpened()) { | |
SetLastError(ERROR_INVALID_HANDLE); | |
return false; | |
} | |
if (NULL == desc) { | |
SetLastError(ERROR_INVALID_PARAMETER); | |
return false; | |
} | |
CopyMemory(desc, usb_interface_descriptor(), sizeof(USB_INTERFACE_DESCRIPTOR)); | |
return true; | |
} | |
bool AdbInterfaceObject::GetEndpointInformation(UCHAR endpoint_index, | |
AdbEndpointInformation* info) { | |
if (!IsOpened()) { | |
SetLastError(ERROR_INVALID_HANDLE); | |
return false; | |
} | |
if (NULL == info) { | |
SetLastError(ERROR_INVALID_PARAMETER); | |
return false; | |
} | |
// Get actual endpoint index for predefined read / write endpoints. | |
if (ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) { | |
endpoint_index = def_read_endpoint_; | |
} else if (ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) { | |
endpoint_index = def_write_endpoint_; | |
} | |
// Query endpoint information | |
WINUSB_PIPE_INFORMATION pipe_info; | |
if (!WinUsb_QueryPipe(winusb_handle(), interface_number(), endpoint_index, | |
&pipe_info)) { | |
return false; | |
} | |
// Save endpoint information into output. | |
info->max_packet_size = pipe_info.MaximumPacketSize; | |
info->max_transfer_size = 0xFFFFFFFF; | |
info->endpoint_address = pipe_info.PipeId; | |
info->polling_interval = pipe_info.Interval; | |
info->setting_index = interface_number(); | |
switch (pipe_info.PipeType) { | |
case UsbdPipeTypeControl: | |
info->endpoint_type = AdbEndpointTypeControl; | |
break; | |
case UsbdPipeTypeIsochronous: | |
info->endpoint_type = AdbEndpointTypeIsochronous; | |
break; | |
case UsbdPipeTypeBulk: | |
info->endpoint_type = AdbEndpointTypeBulk; | |
break; | |
case UsbdPipeTypeInterrupt: | |
info->endpoint_type = AdbEndpointTypeInterrupt; | |
break; | |
default: | |
info->endpoint_type = AdbEndpointTypeInvalid; | |
break; | |
} | |
return true; | |
} | |
ADBAPIHANDLE AdbInterfaceObject::OpenEndpoint( | |
UCHAR endpoint_index, | |
AdbOpenAccessType access_type, | |
AdbOpenSharingMode sharing_mode) { | |
// Convert index into id | |
UCHAR endpoint_id; | |
if ((ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) || | |
(def_read_endpoint_ == endpoint_index)) { | |
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_id = write_endpoint_id_; | |
endpoint_index = def_write_endpoint_; | |
} else { | |
SetLastError(ERROR_INVALID_PARAMETER); | |
return false; | |
} | |
return OpenEndpoint(endpoint_id, endpoint_index); | |
} | |
ADBAPIHANDLE AdbInterfaceObject::OpenEndpoint(UCHAR endpoint_id, | |
UCHAR endpoint_index) { | |
if (!IsOpened()) { | |
SetLastError(ERROR_INVALID_HANDLE); | |
return false; | |
} | |
AdbEndpointObject* adb_endpoint = NULL; | |
try { | |
adb_endpoint = new AdbEndpointObject(this, endpoint_id, endpoint_index); | |
} catch (...) { | |
SetLastError(ERROR_OUTOFMEMORY); | |
return NULL; | |
} | |
ADBAPIHANDLE ret = adb_endpoint->CreateHandle(); | |
adb_endpoint->Release(); | |
return ret; | |
} |