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 <libudev.h> | 5 #include <linux/hidraw.h> |
| 6 #include <sys/ioctl.h> |
| 7 |
6 #include <stdint.h> | 8 #include <stdint.h> |
7 | 9 |
8 #include <string> | 10 #include <string> |
9 #include <vector> | |
10 | 11 |
11 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/files/file_path.h" |
12 #include "base/logging.h" | 14 #include "base/logging.h" |
13 #include "base/platform_file.h" | 15 #include "base/platform_file.h" |
14 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
15 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/string_piece.h" | 18 #include "base/strings/string_piece.h" |
17 #include "base/strings/string_split.h" | 19 #include "base/strings/string_split.h" |
18 #include "device/hid/hid_connection_linux.h" | 20 #include "device/hid/hid_connection_linux.h" |
19 #include "device/hid/hid_device_info.h" | 21 #include "device/hid/hid_device_info.h" |
| 22 #include "device/hid/hid_report_descriptor.h" |
20 #include "device/hid/hid_service_linux.h" | 23 #include "device/hid/hid_service_linux.h" |
21 #include "device/hid/udev_common.h" | 24 #include "device/hid/udev_common.h" |
22 | 25 |
23 namespace device { | 26 namespace device { |
24 | 27 |
25 namespace { | 28 namespace { |
26 | 29 |
27 const char kHIDSubSystem[] = "hid"; | 30 const char kHIDSubSystem[] = "hid"; |
28 | 31 const char kHidrawSubsystem[] = "hidraw"; |
29 const char kHIDID[] = "HID_ID"; | 32 const char kHIDID[] = "HID_ID"; |
30 const char kHIDName[] = "HID_NAME"; | 33 const char kHIDName[] = "HID_NAME"; |
31 const char kHIDUnique[] = "HID_UNIQ"; | 34 const char kHIDUnique[] = "HID_UNIQ"; |
32 | 35 |
33 } // namespace | 36 } // namespace |
34 | 37 |
35 HidServiceLinux::HidServiceLinux() { | 38 HidServiceLinux::HidServiceLinux() { |
36 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance(); | 39 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance(); |
37 monitor->AddObserver(this); | 40 monitor->AddObserver(this); |
38 monitor->Enumerate( | 41 monitor->Enumerate( |
39 base::Bind(&HidServiceLinux::OnDeviceAdded, base::Unretained(this))); | 42 base::Bind(&HidServiceLinux::OnDeviceAdded, base::Unretained(this))); |
40 } | 43 } |
41 | 44 |
42 scoped_refptr<HidConnection> HidServiceLinux::Connect( | 45 scoped_refptr<HidConnection> HidServiceLinux::Connect( |
43 const HidDeviceId& device_id) { | 46 const HidDeviceId& device_id) { |
44 HidDeviceInfo device_info; | 47 HidDeviceInfo device_info; |
45 if (!GetDeviceInfo(device_id, &device_info)) | 48 if (!GetDeviceInfo(device_id, &device_info)) |
46 return NULL; | 49 return NULL; |
47 | 50 |
48 ScopedUdevDevicePtr device = | 51 ScopedUdevDevicePtr device = |
49 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath( | 52 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath( |
50 device_info.device_id); | 53 device_info.device_id); |
51 if (device) | 54 |
52 return new HidConnectionLinux(device_info, device.Pass()); | 55 if (device) { |
| 56 std::string dev_node; |
| 57 if (!FindHidrawDevNode(device.get(), &dev_node)) { |
| 58 LOG(ERROR) << "Cannot open HID device as hidraw device."; |
| 59 return NULL; |
| 60 } |
| 61 return new HidConnectionLinux(device_info, dev_node); |
| 62 } |
| 63 |
53 return NULL; | 64 return NULL; |
54 } | 65 } |
55 | 66 |
56 HidServiceLinux::~HidServiceLinux() { | 67 HidServiceLinux::~HidServiceLinux() { |
57 if (DeviceMonitorLinux::HasInstance()) | 68 if (DeviceMonitorLinux::HasInstance()) |
58 DeviceMonitorLinux::GetInstance()->RemoveObserver(this); | 69 DeviceMonitorLinux::GetInstance()->RemoveObserver(this); |
59 } | 70 } |
60 | 71 |
61 void HidServiceLinux::OnDeviceAdded(udev_device* device) { | 72 void HidServiceLinux::OnDeviceAdded(udev_device* device) { |
62 if (!device) | 73 if (!device) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 } | 105 } |
95 | 106 |
96 str_property = udev_device_get_property_value(device, kHIDUnique); | 107 str_property = udev_device_get_property_value(device, kHIDUnique); |
97 if (str_property != NULL) | 108 if (str_property != NULL) |
98 device_info.serial_number = str_property; | 109 device_info.serial_number = str_property; |
99 | 110 |
100 str_property = udev_device_get_property_value(device, kHIDName); | 111 str_property = udev_device_get_property_value(device, kHIDName); |
101 if (str_property != NULL) | 112 if (str_property != NULL) |
102 device_info.product_name = str_property; | 113 device_info.product_name = str_property; |
103 | 114 |
| 115 std::string dev_node; |
| 116 if (!FindHidrawDevNode(device, &dev_node)) { |
| 117 LOG(ERROR) << "Cannot open HID device as hidraw device."; |
| 118 return; |
| 119 } |
| 120 |
| 121 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; |
| 122 |
| 123 base::File device_file(base::FilePath(dev_node), flags); |
| 124 if (!device_file.IsValid()) { |
| 125 LOG(ERROR) << device_file.error_details(); |
| 126 return; |
| 127 } |
| 128 |
| 129 int desc_size = 0; |
| 130 int res = ioctl(device_file.GetPlatformFile(), HIDIOCGRDESCSIZE, &desc_size); |
| 131 if (res < 0) { |
| 132 LOG(ERROR) << "HIDIOCGRDESCSIZE failed."; |
| 133 device_file.Close(); |
| 134 return; |
| 135 } |
| 136 |
| 137 hidraw_report_descriptor rpt_desc; |
| 138 rpt_desc.size = desc_size; |
| 139 |
| 140 res = ioctl(device_file.GetPlatformFile(), HIDIOCGRDESC, &rpt_desc); |
| 141 if (res < 0) { |
| 142 LOG(ERROR) << "HIDIOCGRDESC failed."; |
| 143 device_file.Close(); |
| 144 return; |
| 145 } |
| 146 |
| 147 device_file.Close(); |
| 148 |
| 149 HidReportDescriptor report_descriptor(rpt_desc.value, rpt_desc.size); |
| 150 report_descriptor.GetTopLevelCollections(&device_info.usages); |
| 151 |
104 AddDevice(device_info); | 152 AddDevice(device_info); |
105 } | 153 } |
106 | 154 |
107 void HidServiceLinux::OnDeviceRemoved(udev_device* device) { | 155 void HidServiceLinux::OnDeviceRemoved(udev_device* device) { |
108 const char* device_path = udev_device_get_syspath(device);; | 156 const char* device_path = udev_device_get_syspath(device);; |
109 if (device_path) | 157 if (device_path) |
110 RemoveDevice(device_path); | 158 RemoveDevice(device_path); |
111 } | 159 } |
112 | 160 |
| 161 bool HidServiceLinux::FindHidrawDevNode(udev_device* parent, |
| 162 std::string* result) { |
| 163 udev* udev = udev_device_get_udev(parent); |
| 164 if (!udev) { |
| 165 return false; |
| 166 } |
| 167 ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev)); |
| 168 if (!enumerate) { |
| 169 return false; |
| 170 } |
| 171 if (udev_enumerate_add_match_subsystem(enumerate.get(), kHidrawSubsystem)) { |
| 172 return false; |
| 173 } |
| 174 if (udev_enumerate_scan_devices(enumerate.get())) { |
| 175 return false; |
| 176 } |
| 177 std::string parent_path(udev_device_get_devpath(parent)); |
| 178 if (parent_path.length() == 0 || *parent_path.rbegin() != '/') |
| 179 parent_path += '/'; |
| 180 udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get()); |
| 181 for (udev_list_entry* i = devices; i != NULL; |
| 182 i = udev_list_entry_get_next(i)) { |
| 183 ScopedUdevDevicePtr hid_dev( |
| 184 udev_device_new_from_syspath(udev, udev_list_entry_get_name(i))); |
| 185 const char* raw_path = udev_device_get_devnode(hid_dev.get()); |
| 186 std::string device_path = udev_device_get_devpath(hid_dev.get()); |
| 187 if (raw_path && |
| 188 !device_path.compare(0, parent_path.length(), parent_path)) { |
| 189 std::string sub_path = device_path.substr(parent_path.length()); |
| 190 if (sub_path.substr(0, sizeof(kHidrawSubsystem) - 1) == |
| 191 kHidrawSubsystem) { |
| 192 *result = raw_path; |
| 193 return true; |
| 194 } |
| 195 } |
| 196 } |
| 197 |
| 198 return false; |
| 199 } |
| 200 |
113 } // namespace dev | 201 } // namespace dev |
OLD | NEW |