adb_helper_routines.cpp revision 59fc68ba26dca2543bd96a71254e6b124243fb66
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/** \file
18  This file consists of implementation of helper routines used
19  in the API.
20*/
21
22#include "stdafx.h"
23#include "adb_api.h"
24#include "adb_api_legacy.h"
25#include "adb_helper_routines.h"
26#include "adb_interface_enum.h"
27
28bool EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info,
29                               GUID class_id,
30                               bool exclude_removed,
31                               bool active_only,
32                               AdbEnumInterfaceArray* interfaces) {
33  AdbEnumInterfaceArray tmp;
34  bool ret = false;
35
36  // Enumerate interfaces on this device
37  for (ULONG index = 0; ; index++) {
38    SP_DEVICE_INTERFACE_DATA interface_data;
39    interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
40
41    // SetupDiEnumDeviceInterfaces() returns information about device
42    // interfaces exposed by one or more devices defined by our interface
43    // class. Each call returns information about one interface. The routine
44    // can be called repeatedly to get information about several interfaces
45    // exposed by one or more devices.
46    if (SetupDiEnumDeviceInterfaces(hardware_dev_info,
47                                    0,
48                                    &class_id,
49                                    index,
50                                    &interface_data)) {
51      // Satisfy "exclude removed" and "active only" filters.
52      if ((!exclude_removed || (0 == (interface_data.Flags & SPINT_REMOVED))) &&
53          (!active_only || (interface_data.Flags & SPINT_ACTIVE))) {
54        std::wstring dev_name;
55
56        if (GetUsbDeviceName(hardware_dev_info, &interface_data, &dev_name)) {
57          try {
58            // Add new entry to the array
59            tmp.push_back(AdbInstanceEnumEntry(dev_name.c_str(),
60                                               interface_data.InterfaceClassGuid,
61                                               interface_data.Flags));
62          } catch (... ) {
63            SetLastError(ERROR_OUTOFMEMORY);
64            break;
65          }
66        } else {
67          // Something went wrong in getting device name
68          break;
69        }
70      }
71    } else {
72      if (ERROR_NO_MORE_ITEMS == GetLastError()) {
73        // There are no more items in the list. Enum is completed.
74        ret = true;
75        break;
76      } else {
77        // Something went wrong in SDK enum
78        break;
79      }
80    }
81  }
82
83  // On success, swap temp array with the returning one
84  if (ret)
85    interfaces->swap(tmp);
86
87  return ret;
88}
89
90bool EnumerateDeviceInterfaces(GUID class_id,
91                               ULONG flags,
92                               bool exclude_removed,
93                               bool active_only,
94                               AdbEnumInterfaceArray* interfaces) {
95  // Open a handle to the plug and play dev node.
96  // SetupDiGetClassDevs() returns a device information set that
97  // contains info on all installed devices of a specified class.
98  HDEVINFO hardware_dev_info =
99    SetupDiGetClassDevs(&class_id, NULL, NULL, flags);
100
101  bool ret = false;
102
103  if (INVALID_HANDLE_VALUE != hardware_dev_info) {
104    // Do the enum
105    ret = EnumerateDeviceInterfaces(hardware_dev_info,
106                                    class_id,
107                                    exclude_removed,
108                                    active_only,
109                                    interfaces);
110
111    // Preserve last error accross hardware_dev_info destruction
112    ULONG error_to_report = ret ? NO_ERROR : GetLastError();
113
114    SetupDiDestroyDeviceInfoList(hardware_dev_info);
115
116    if (NO_ERROR != error_to_report)
117      SetLastError(error_to_report);
118  }
119
120  return ret;
121}
122
123bool GetUsbDeviceDetails(
124    HDEVINFO hardware_dev_info,
125    PSP_DEVICE_INTERFACE_DATA dev_info_data,
126    PSP_DEVICE_INTERFACE_DETAIL_DATA* dev_info_detail_data) {
127  ULONG required_len = 0;
128
129  // First query for the structure size. At this point we expect this call
130  // to fail with ERROR_INSUFFICIENT_BUFFER error code.
131  if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,
132                                      dev_info_data,
133                                      NULL,
134                                      0,
135                                      &required_len,
136                                      NULL)) {
137    return false;
138  }
139
140  if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
141    return false;
142
143  // Allocate buffer for the structure
144  PSP_DEVICE_INTERFACE_DETAIL_DATA buffer =
145    reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(required_len));
146
147  if (NULL == buffer) {
148    SetLastError(ERROR_OUTOFMEMORY);
149    return false;
150  }
151
152  buffer->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
153
154  // Retrieve the information from Plug and Play.
155  if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,
156                                      dev_info_data,
157                                      buffer,
158                                      required_len,
159                                      &required_len,
160                                      NULL)) {
161    *dev_info_detail_data = buffer;
162    return true;
163  } else {
164    // Free the buffer if this call failed
165    free(buffer);
166
167    return false;
168  }
169}
170
171bool GetUsbDeviceName(HDEVINFO hardware_dev_info,
172                      PSP_DEVICE_INTERFACE_DATA dev_info_data,
173                      std::wstring* name) {
174  PSP_DEVICE_INTERFACE_DETAIL_DATA func_class_dev_data = NULL;
175  if (!GetUsbDeviceDetails(hardware_dev_info,
176                           dev_info_data,
177                           &func_class_dev_data)) {
178    return false;
179  }
180
181  try {
182    *name = func_class_dev_data->DevicePath;
183  } catch (...) {
184    SetLastError(ERROR_OUTOFMEMORY);
185  }
186
187  free(func_class_dev_data);
188
189  return !name->empty();
190}
191
192bool IsLegacyInterface(const wchar_t* interface_name) {
193  // Open USB device for this intefface
194  HANDLE usb_device_handle = CreateFile(interface_name,
195                                        GENERIC_READ | GENERIC_WRITE,
196                                        FILE_SHARE_READ | FILE_SHARE_WRITE,
197                                        NULL,
198                                        OPEN_EXISTING,
199                                        0,
200                                        NULL);
201  if (INVALID_HANDLE_VALUE == usb_device_handle)
202    return NULL;
203
204  // Try to issue ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR IOCTL that is supported
205  // by the legacy driver, but is not implemented in the WinUsb driver.
206  DWORD ret_bytes = 0;
207  USB_DEVICE_DESCRIPTOR descriptor;
208  BOOL ret = DeviceIoControl(usb_device_handle,
209                             ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR,
210                             NULL, 0,
211                             &descriptor,
212                             sizeof(descriptor),
213                             &ret_bytes,
214                             NULL);
215  ::CloseHandle(usb_device_handle);
216
217  // If IOCTL succeeded we've got legacy driver underneath.
218  return ret ? true : false;
219}
220