/*
* 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 helper routines used
in the API.
*/
#include "stdafx.h"
#include "adb_api.h"
#include "adb_api_legacy.h"
#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,
bool active_only,
AdbEnumInterfaceArray* interfaces) {
AdbEnumInterfaceArray tmp;
bool ret = false;
// Enumerate interfaces on this device
for (ULONG index = 0; ; index++) {
SP_DEVICE_INTERFACE_DATA interface_data;
interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
// SetupDiEnumDeviceInterfaces() returns information about device
// interfaces exposed by one or more devices defined by our interface
// class. Each call returns information about one interface. The routine
// can be called repeatedly to get information about several interfaces
// exposed by one or more devices.
if (SetupDiEnumDeviceInterfaces(hardware_dev_info,
0,
&class_id,
index,
&interface_data)) {
// Satisfy "exclude removed" and "active only" filters.
if ((!exclude_removed || (0 == (interface_data.Flags & SPINT_REMOVED))) &&
(!active_only || (interface_data.Flags & SPINT_ACTIVE))) {
std::wstring dev_name;
if (GetUsbDeviceName(hardware_dev_info, &interface_data, &dev_name)) {
try {
// Add new entry to the array
tmp.push_back(AdbInstanceEnumEntry(dev_name.c_str(),
interface_data.InterfaceClassGuid,
interface_data.Flags));
} catch (... ) {
SetLastError(ERROR_OUTOFMEMORY);
break;
}
} else {
// Something went wrong in getting device name
break;
}
}
} else {
if (ERROR_NO_MORE_ITEMS == GetLastError()) {
// There are no more items in the list. Enum is completed.
ret = true;
break;
} else {
// Something went wrong in SDK enum
break;
}
}
}
// On success, swap temp array with the returning one
if (ret)
interfaces->swap(tmp);
return ret;
}
bool EnumerateDeviceInterfaces(GUID class_id,
ULONG flags,
bool exclude_removed,
bool active_only,
AdbEnumInterfaceArray* interfaces) {
// Open a handle to the plug and play dev node.
// SetupDiGetClassDevs() returns a device information set that
// contains info on all installed devices of a specified class.
HDEVINFO hardware_dev_info =
SetupDiGetClassDevs(&class_id, NULL, NULL, flags);
bool ret = false;
if (INVALID_HANDLE_VALUE != hardware_dev_info) {
// Do the enum
ret = EnumerateDeviceInterfaces(hardware_dev_info,
class_id,
exclude_removed,
active_only,
interfaces);
// Preserve last error accross hardware_dev_info destruction
ULONG error_to_report = ret ? NO_ERROR : GetLastError();
SetupDiDestroyDeviceInfoList(hardware_dev_info);
if (NO_ERROR != error_to_report)
SetLastError(error_to_report);
}
return ret;
}
bool GetUsbDeviceDetails(
HDEVINFO hardware_dev_info,
PSP_DEVICE_INTERFACE_DATA dev_info_data,
PSP_DEVICE_INTERFACE_DETAIL_DATA* dev_info_detail_data) {
ULONG required_len = 0;
// First query for the structure size. At this point we expect this call
// to fail with ERROR_INSUFFICIENT_BUFFER error code.
if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,
dev_info_data,
NULL,
0,
&required_len,
NULL)) {
return false;
}
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
return false;
// Allocate buffer for the structure
PSP_DEVICE_INTERFACE_DETAIL_DATA buffer =
reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(required_len));
if (NULL == buffer) {
SetLastError(ERROR_OUTOFMEMORY);
return false;
}
buffer->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Retrieve the information from Plug and Play.
if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,
dev_info_data,
buffer,
required_len,
&required_len,
NULL)) {
*dev_info_detail_data = buffer;
return true;
} else {
// Free the buffer if this call failed
free(buffer);
return false;
}
}
bool GetUsbDeviceName(HDEVINFO hardware_dev_info,
PSP_DEVICE_INTERFACE_DATA dev_info_data,
std::wstring* name) {
PSP_DEVICE_INTERFACE_DETAIL_DATA func_class_dev_data = NULL;
if (!GetUsbDeviceDetails(hardware_dev_info,
dev_info_data,
&func_class_dev_data)) {
return false;
}
try {
*name = func_class_dev_data->DevicePath;
} catch (...) {
SetLastError(ERROR_OUTOFMEMORY);
}
free(func_class_dev_data);
return !name->empty();
}
bool IsLegacyInterface(const wchar_t* interface_name) {
// Open USB device for this intefface
HANDLE usb_device_handle = CreateFile(interface_name,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (INVALID_HANDLE_VALUE == usb_device_handle)
return NULL;
// Try to issue ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR IOCTL that is supported
// by the legacy driver, but is not implemented in the WinUsb driver.
DWORD ret_bytes = 0;
USB_DEVICE_DESCRIPTOR descriptor;
BOOL ret = DeviceIoControl(usb_device_handle,
ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR,
NULL, 0,
&descriptor,
sizeof(descriptor),
&ret_bytes,
NULL);
::CloseHandle(usb_device_handle);
// If IOCTL succeeded we've got legacy driver underneath.
return ret ? true : false;
}