/* | |
* 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; | |
} |