| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 |  | 
| 3 // found in the LICENSE file. |  | 
| 4 |  | 
| 5 #include <libudev.h> |  | 
| 6 #include <string> |  | 
| 7 #include <vector> |  | 
| 8 |  | 
| 9 #include "base/basictypes.h" |  | 
| 10 #include "base/bind.h" |  | 
| 11 #include "base/callback.h" |  | 
| 12 #include "base/logging.h" |  | 
| 13 #include "base/memory/scoped_vector.h" |  | 
| 14 #include "base/platform_file.h" |  | 
| 15 #include "base/strings/string_number_conversions.h" |  | 
| 16 #include "base/strings/string_piece.h" |  | 
| 17 #include "base/strings/string_split.h" |  | 
| 18 #include "base/threading/thread_restrictions.h" |  | 
| 19 #include "device/hid/hid_connection.h" |  | 
| 20 #include "device/hid/hid_connection_linux.h" |  | 
| 21 #include "device/hid/hid_device_info.h" |  | 
| 22 #include "device/hid/hid_service_linux.h" |  | 
| 23 |  | 
| 24 namespace device { |  | 
| 25 |  | 
| 26 namespace { |  | 
| 27 |  | 
| 28 const char kUdevName[] = "udev"; |  | 
| 29 const char kUdevActionAdd[] = "add"; |  | 
| 30 const char kUdevActionRemove[] = "remove"; |  | 
| 31 const char kHIDSubSystem[] = "hid"; |  | 
| 32 |  | 
| 33 const char kHIDID[] = "HID_ID"; |  | 
| 34 const char kHIDName[] = "HID_NAME"; |  | 
| 35 const char kHIDUnique[] = "HID_UNIQ"; |  | 
| 36 |  | 
| 37 } // namespace |  | 
| 38 |  | 
| 39 HidServiceLinux::HidServiceLinux() { |  | 
| 40   udev_.reset(udev_new()); |  | 
| 41   if (!udev_) { |  | 
| 42     LOG(ERROR) << "Failed to create udev."; |  | 
| 43     return; |  | 
| 44   } |  | 
| 45   monitor_.reset(udev_monitor_new_from_netlink(udev_.get(), kUdevName)); |  | 
| 46   if (!monitor_) { |  | 
| 47     LOG(ERROR) << "Failed to create udev monitor."; |  | 
| 48     return; |  | 
| 49   } |  | 
| 50   int ret = udev_monitor_filter_add_match_subsystem_devtype( |  | 
| 51       monitor_.get(), |  | 
| 52       kHIDSubSystem, |  | 
| 53       NULL); |  | 
| 54   if (ret != 0) { |  | 
| 55     LOG(ERROR) << "Failed to add udev monitor filter."; |  | 
| 56     return; |  | 
| 57   } |  | 
| 58 |  | 
| 59   ret = udev_monitor_enable_receiving(monitor_.get()); |  | 
| 60   if (ret != 0) { |  | 
| 61     LOG(ERROR) << "Failed to start udev monitoring."; |  | 
| 62     return; |  | 
| 63   } |  | 
| 64 |  | 
| 65   monitor_fd_ = udev_monitor_get_fd(monitor_.get()); |  | 
| 66   if (monitor_fd_ <= 0) { |  | 
| 67     LOG(ERROR) << "Failed to start udev monitoring."; |  | 
| 68     return; |  | 
| 69   } |  | 
| 70 |  | 
| 71   if (!base::MessageLoopForIO::current()->WatchFileDescriptor( |  | 
| 72       monitor_fd_, |  | 
| 73       true, |  | 
| 74       base::MessageLoopForIO::WATCH_READ, |  | 
| 75       &monitor_watcher_, |  | 
| 76       this)) |  | 
| 77     return; |  | 
| 78 |  | 
| 79   Enumerate(); |  | 
| 80 } |  | 
| 81 |  | 
| 82 HidServiceLinux::~HidServiceLinux() { |  | 
| 83   monitor_watcher_.StopWatchingFileDescriptor(); |  | 
| 84   close(monitor_fd_); |  | 
| 85 } |  | 
| 86 |  | 
| 87 void HidServiceLinux::Enumerate() { |  | 
| 88   scoped_ptr<udev_enumerate, UdevEnumerateDeleter> enumerate( |  | 
| 89       udev_enumerate_new(udev_.get())); |  | 
| 90 |  | 
| 91   if (!enumerate) { |  | 
| 92     LOG(ERROR) << "Failed to enumerate devices."; |  | 
| 93     return; |  | 
| 94   } |  | 
| 95 |  | 
| 96   if (udev_enumerate_add_match_subsystem(enumerate.get(), kHIDSubSystem)) { |  | 
| 97     LOG(ERROR) << "Failed to enumerate devices."; |  | 
| 98     return; |  | 
| 99   } |  | 
| 100 |  | 
| 101   if (udev_enumerate_scan_devices(enumerate.get()) != 0) { |  | 
| 102     LOG(ERROR) << "Failed to enumerate devices."; |  | 
| 103     return; |  | 
| 104   } |  | 
| 105 |  | 
| 106   // This list is managed by |enumerate|. |  | 
| 107   udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get()); |  | 
| 108   for (udev_list_entry* i = devices; i != NULL; |  | 
| 109       i = udev_list_entry_get_next(i)) { |  | 
| 110     ScopedUdevDevicePtr hid_dev( |  | 
| 111         udev_device_new_from_syspath(udev_.get(), udev_list_entry_get_name(i))); |  | 
| 112     if (hid_dev) { |  | 
| 113       PlatformDeviceAdd(hid_dev.get()); |  | 
| 114     } |  | 
| 115   } |  | 
| 116 |  | 
| 117   initialized_ = true; |  | 
| 118 } |  | 
| 119 |  | 
| 120 void HidServiceLinux::PlatformDeviceAdd(udev_device* device) { |  | 
| 121   if (!device) |  | 
| 122     return; |  | 
| 123 |  | 
| 124   const char* device_id = udev_device_get_syspath(device); |  | 
| 125   if (!device_id) |  | 
| 126     return; |  | 
| 127 |  | 
| 128 |  | 
| 129   HidDeviceInfo device_info; |  | 
| 130   device_info.device_id = device_id; |  | 
| 131 |  | 
| 132   uint32 int_property = 0; |  | 
| 133   const char* str_property = NULL; |  | 
| 134 |  | 
| 135   const char* hid_id = udev_device_get_property_value(device, kHIDID); |  | 
| 136   if (!hid_id) |  | 
| 137     return; |  | 
| 138 |  | 
| 139   std::vector<std::string> parts; |  | 
| 140   base::SplitString(hid_id, ':', &parts); |  | 
| 141   if (parts.size() != 3) { |  | 
| 142     return; |  | 
| 143   } |  | 
| 144 |  | 
| 145   if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) { |  | 
| 146     device_info.vendor_id = int_property; |  | 
| 147   } |  | 
| 148 |  | 
| 149   if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) { |  | 
| 150     device_info.product_id = int_property; |  | 
| 151   } |  | 
| 152 |  | 
| 153   str_property = udev_device_get_property_value(device, kHIDUnique); |  | 
| 154   if (str_property != NULL) |  | 
| 155     device_info.serial_number = str_property; |  | 
| 156 |  | 
| 157   str_property = udev_device_get_property_value(device, kHIDName); |  | 
| 158   if (str_property != NULL) |  | 
| 159     device_info.product_name = str_property; |  | 
| 160 |  | 
| 161   AddDevice(device_info); |  | 
| 162 } |  | 
| 163 |  | 
| 164 void HidServiceLinux::PlatformDeviceRemove(udev_device* raw_dev) { |  | 
| 165   // The returned the device is not referenced. |  | 
| 166   udev_device* hid_dev = |  | 
| 167       udev_device_get_parent_with_subsystem_devtype(raw_dev, "hid", NULL); |  | 
| 168 |  | 
| 169   if (!hid_dev) |  | 
| 170     return; |  | 
| 171 |  | 
| 172   const char* device_id = NULL; |  | 
| 173   device_id = udev_device_get_syspath(hid_dev); |  | 
| 174   if (device_id == NULL) |  | 
| 175     return; |  | 
| 176 |  | 
| 177   RemoveDevice(device_id); |  | 
| 178 } |  | 
| 179 |  | 
| 180 scoped_refptr<HidConnection> HidServiceLinux::Connect(std::string device_id) { |  | 
| 181   if (!ContainsKey(devices_, device_id)) |  | 
| 182     return NULL; |  | 
| 183   ScopedUdevDevicePtr hid_device( |  | 
| 184       udev_device_new_from_syspath(udev_.get(), device_id.c_str())); |  | 
| 185   if (hid_device) { |  | 
| 186     scoped_refptr<HidConnectionLinux> connection = |  | 
| 187         new HidConnectionLinux(devices_[device_id], hid_device.Pass()); |  | 
| 188     if (connection->initialized()) |  | 
| 189       return connection; |  | 
| 190   } |  | 
| 191   return NULL; |  | 
| 192 } |  | 
| 193 |  | 
| 194 void HidServiceLinux::OnFileCanReadWithoutBlocking(int fd) { |  | 
| 195   DCHECK_EQ(monitor_fd_, fd); |  | 
| 196 |  | 
| 197   ScopedUdevDevicePtr dev(udev_monitor_receive_device(monitor_.get())); |  | 
| 198   if (!dev) |  | 
| 199     return; |  | 
| 200 |  | 
| 201   std::string action(udev_device_get_action(dev.get())); |  | 
| 202   if (action == kUdevActionAdd) { |  | 
| 203     PlatformDeviceAdd(dev.get()); |  | 
| 204   } else if (action == kUdevActionRemove) { |  | 
| 205     PlatformDeviceRemove(dev.get()); |  | 
| 206   } |  | 
| 207 } |  | 
| 208 |  | 
| 209 void HidServiceLinux::OnFileCanWriteWithoutBlocking(int fd) {} |  | 
| 210 |  | 
| 211 } // namespace dev |  | 
| OLD | NEW | 
|---|