OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "device/serial/serial_device_enumerator_win.h" | 5 #include "device/serial/serial_device_enumerator_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
| 9 #include <ntddser.h> |
| 10 #include <setupapi.h> |
| 11 |
9 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
10 #include "base/strings/string_util.h" | 13 #include "base/strings/string_number_conversions.h" |
11 #include "base/strings/stringprintf.h" | |
12 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
13 #include "base/win/registry.h" | 15 #include "third_party/re2/re2/re2.h" |
14 | 16 |
15 namespace device { | 17 namespace device { |
16 | 18 |
| 19 namespace { |
| 20 |
| 21 // Searches the specified device info for a property with the specified key, |
| 22 // assigns the result to value, and returns whether the operation was |
| 23 // successful. |
| 24 bool GetProperty(HDEVINFO dev_info, |
| 25 SP_DEVINFO_DATA dev_info_data, |
| 26 const int key, |
| 27 std::string* value) { |
| 28 // We don't know how much space the property's value will take up, so we call |
| 29 // the property retrieval function once to fetch the size of the required |
| 30 // value buffer, then again once we've allocated a sufficiently large buffer. |
| 31 DWORD buffer_size = 0; |
| 32 SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, key, nullptr, |
| 33 nullptr, buffer_size, &buffer_size); |
| 34 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) |
| 35 return false; |
| 36 |
| 37 scoped_ptr<wchar_t[]> buffer(new wchar_t[buffer_size]); |
| 38 if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, key, nullptr, |
| 39 reinterpret_cast<PBYTE>(buffer.get()), |
| 40 buffer_size, nullptr)) |
| 41 return false; |
| 42 |
| 43 *value = base::WideToUTF8(buffer.get()); |
| 44 return true; |
| 45 } |
| 46 |
| 47 // Searches for the COM port in the device's friendly name, assigns its value to |
| 48 // com_port, and returns whether the operation was successful. |
| 49 bool GetCOMPort(const std::string friendly_name, std::string* com_port) { |
| 50 return RE2::PartialMatch(friendly_name, ".* \\((COM[0-9]+)\\)", com_port); |
| 51 } |
| 52 |
| 53 // Searches for the display name in the device's friendly name, assigns its |
| 54 // value to display_name, and returns whether the operation was successful. |
| 55 bool GetDisplayName(const std::string friendly_name, |
| 56 std::string* display_name) { |
| 57 return RE2::PartialMatch(friendly_name, "(.*) \\(COM[0-9]+\\)", display_name); |
| 58 } |
| 59 |
| 60 // Searches for the vendor ID in the device's hardware ID, assigns its value to |
| 61 // vendor_id, and returns whether the operation was successful. |
| 62 bool GetVendorID(const std::string hardware_id, uint32_t* vendor_id) { |
| 63 std::string vendor_id_str; |
| 64 return RE2::PartialMatch(hardware_id, "VID_([0-9]+)", &vendor_id_str) && |
| 65 base::HexStringToUInt(vendor_id_str, vendor_id); |
| 66 } |
| 67 |
| 68 // Searches for the product ID in the device's product ID, assigns its value to |
| 69 // product_id, and returns whether the operation was successful. |
| 70 bool GetProductID(const std::string hardware_id, uint32_t* product_id) { |
| 71 std::string product_id_str; |
| 72 return RE2::PartialMatch(hardware_id, "PID_([0-9]+)", &product_id_str) && |
| 73 base::HexStringToUInt(product_id_str, product_id); |
| 74 } |
| 75 |
| 76 } // namespace |
| 77 |
17 // static | 78 // static |
18 scoped_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() { | 79 scoped_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() { |
19 return scoped_ptr<SerialDeviceEnumerator>(new SerialDeviceEnumeratorWin()); | 80 return scoped_ptr<SerialDeviceEnumerator>(new SerialDeviceEnumeratorWin()); |
20 } | 81 } |
21 | 82 |
22 SerialDeviceEnumeratorWin::SerialDeviceEnumeratorWin() {} | 83 SerialDeviceEnumeratorWin::SerialDeviceEnumeratorWin() {} |
23 | 84 |
24 SerialDeviceEnumeratorWin::~SerialDeviceEnumeratorWin() {} | 85 SerialDeviceEnumeratorWin::~SerialDeviceEnumeratorWin() {} |
25 | 86 |
26 // TODO(rockot): Query the system for more information than just device paths. | |
27 // This may or may not require using a different strategy than scanning the | |
28 // registry location below. | |
29 mojo::Array<serial::DeviceInfoPtr> SerialDeviceEnumeratorWin::GetDevices() { | 87 mojo::Array<serial::DeviceInfoPtr> SerialDeviceEnumeratorWin::GetDevices() { |
30 base::win::RegistryValueIterator iter_key( | |
31 HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM\\"); | |
32 mojo::Array<serial::DeviceInfoPtr> devices(0); | 88 mojo::Array<serial::DeviceInfoPtr> devices(0); |
33 for (; iter_key.Valid(); ++iter_key) { | 89 |
| 90 // Make a device interface query to find all serial devices. |
| 91 HDEVINFO dev_info = |
| 92 SetupDiGetClassDevs(&GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, 0, 0, |
| 93 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); |
| 94 if (dev_info == INVALID_HANDLE_VALUE) |
| 95 return devices.Pass(); |
| 96 |
| 97 SP_DEVINFO_DATA dev_info_data; |
| 98 dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA); |
| 99 for (DWORD i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { |
| 100 std::string friendly_name, com_port; |
| 101 // SPDRP_FRIENDLYNAME looks like "USB_SERIAL_PORT (COM3)". |
| 102 if (!GetProperty(dev_info, dev_info_data, SPDRP_FRIENDLYNAME, |
| 103 &friendly_name) || |
| 104 !GetCOMPort(friendly_name, &com_port)) |
| 105 // In Windows, the COM port is the path used to uniquely identify the |
| 106 // serial device. If the COM can't be found, ignore the device. |
| 107 continue; |
| 108 |
34 serial::DeviceInfoPtr info(serial::DeviceInfo::New()); | 109 serial::DeviceInfoPtr info(serial::DeviceInfo::New()); |
35 info->path = base::UTF16ToASCII(iter_key.Value()); | 110 info->path = com_port; |
| 111 |
| 112 std::string display_name; |
| 113 if (GetDisplayName(friendly_name, &display_name)) |
| 114 info->display_name = display_name; |
| 115 |
| 116 std::string hardware_id; |
| 117 // SPDRP_HARDWAREID looks like "FTDIBUS\COMPORT&VID_0403&PID_6001". |
| 118 if (GetProperty(dev_info, dev_info_data, SPDRP_HARDWAREID, &hardware_id)) { |
| 119 uint32_t vendor_id, product_id; |
| 120 if (GetVendorID(hardware_id, &vendor_id)) { |
| 121 info->has_vendor_id = true; |
| 122 info->vendor_id = vendor_id; |
| 123 } |
| 124 if (GetProductID(hardware_id, &product_id)) { |
| 125 info->has_product_id = true; |
| 126 info->product_id = product_id; |
| 127 } |
| 128 } |
| 129 |
36 devices.push_back(info.Pass()); | 130 devices.push_back(info.Pass()); |
37 } | 131 } |
| 132 |
| 133 SetupDiDestroyDeviceInfoList(dev_info); |
38 return devices.Pass(); | 134 return devices.Pass(); |
39 } | 135 } |
40 | 136 |
41 } // namespace device | 137 } // namespace device |
OLD | NEW |