You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
9.0 KiB
275 lines
9.0 KiB
/*
|
|
* 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;
|
|
}
|