| OLD | NEW |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/hid/hid_connection_linux.h" | 5 #include "device/hid/hid_connection_linux.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <linux/hidraw.h> | 8 #include <linux/hidraw.h> |
| 9 #include <sys/ioctl.h> | 9 #include <sys/ioctl.h> |
| 10 | 10 |
| 11 #include <string> | 11 #include <string> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
| 15 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 16 #include "base/message_loop/message_pump_libevent.h" | 16 #include "base/message_loop/message_pump_libevent.h" |
| 17 #include "base/posix/eintr_wrapper.h" | 17 #include "base/posix/eintr_wrapper.h" |
| 18 #include "base/thread_task_runner_handle.h" | 18 #include "base/thread_task_runner_handle.h" |
| 19 #include "base/threading/thread_restrictions.h" | 19 #include "base/threading/thread_restrictions.h" |
| 20 #include "components/device_event_log/device_event_log.h" |
| 20 #include "device/hid/hid_service.h" | 21 #include "device/hid/hid_service.h" |
| 21 | 22 |
| 22 // These are already defined in newer versions of linux/hidraw.h. | 23 // These are already defined in newer versions of linux/hidraw.h. |
| 23 #ifndef HIDIOCSFEATURE | 24 #ifndef HIDIOCSFEATURE |
| 24 #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x06, len) | 25 #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x06, len) |
| 25 #endif | 26 #endif |
| 26 #ifndef HIDIOCGFEATURE | 27 #ifndef HIDIOCGFEATURE |
| 27 #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x07, len) | 28 #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x07, len) |
| 28 #endif | 29 #endif |
| 29 | 30 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 50 | 51 |
| 51 // Starts the FileDescriptorWatcher that reads input events from the device. | 52 // Starts the FileDescriptorWatcher that reads input events from the device. |
| 52 // Must be called on a thread that has a base::MessageLoopForIO. The helper | 53 // Must be called on a thread that has a base::MessageLoopForIO. The helper |
| 53 // object is owned by the thread where it was started. | 54 // object is owned by the thread where it was started. |
| 54 void Start() { | 55 void Start() { |
| 55 base::ThreadRestrictions::AssertIOAllowed(); | 56 base::ThreadRestrictions::AssertIOAllowed(); |
| 56 thread_checker_.DetachFromThread(); | 57 thread_checker_.DetachFromThread(); |
| 57 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | 58 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( |
| 58 platform_file_, true, base::MessageLoopForIO::WATCH_READ, | 59 platform_file_, true, base::MessageLoopForIO::WATCH_READ, |
| 59 &file_watcher_, this)) { | 60 &file_watcher_, this)) { |
| 60 LOG(ERROR) << "Failed to start watching device file."; | 61 HID_LOG(ERROR) << "Failed to start watching device file."; |
| 61 } | 62 } |
| 62 } | 63 } |
| 63 | 64 |
| 64 private: | 65 private: |
| 65 // base::MessagePumpLibevent::Watcher implementation. | 66 // base::MessagePumpLibevent::Watcher implementation. |
| 66 void OnFileCanReadWithoutBlocking(int fd) override { | 67 void OnFileCanReadWithoutBlocking(int fd) override { |
| 67 DCHECK(thread_checker_.CalledOnValidThread()); | 68 DCHECK(thread_checker_.CalledOnValidThread()); |
| 68 DCHECK_EQ(fd, platform_file_); | 69 DCHECK_EQ(fd, platform_file_); |
| 69 | 70 |
| 70 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(report_buffer_size_)); | 71 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(report_buffer_size_)); |
| 71 char* data = buffer->data(); | 72 char* data = buffer->data(); |
| 72 size_t length = report_buffer_size_; | 73 size_t length = report_buffer_size_; |
| 73 if (!has_report_id_) { | 74 if (!has_report_id_) { |
| 74 // Linux will not prefix the buffer with a report ID if report IDs are not | 75 // Linux will not prefix the buffer with a report ID if report IDs are not |
| 75 // used by the device. Prefix the buffer with 0. | 76 // used by the device. Prefix the buffer with 0. |
| 76 *data++ = 0; | 77 *data++ = 0; |
| 77 length--; | 78 length--; |
| 78 } | 79 } |
| 79 | 80 |
| 80 ssize_t bytes_read = HANDLE_EINTR(read(platform_file_, data, length)); | 81 ssize_t bytes_read = HANDLE_EINTR(read(platform_file_, data, length)); |
| 81 if (bytes_read < 0) { | 82 if (bytes_read < 0) { |
| 82 if (errno != EAGAIN) { | 83 if (errno != EAGAIN) { |
| 83 VPLOG(1) << "Read failed"; | 84 HID_PLOG(EVENT) << "Read failed"; |
| 84 // This assumes that the error is unrecoverable and disables reading | 85 // This assumes that the error is unrecoverable and disables reading |
| 85 // from the device until it has been re-opened. | 86 // from the device until it has been re-opened. |
| 86 // TODO(reillyg): Investigate starting and stopping the file descriptor | 87 // TODO(reillyg): Investigate starting and stopping the file descriptor |
| 87 // watcher in response to pending read requests so that per-request | 88 // watcher in response to pending read requests so that per-request |
| 88 // errors can be returned to the client. | 89 // errors can be returned to the client. |
| 89 file_watcher_.StopWatchingFileDescriptor(); | 90 file_watcher_.StopWatchingFileDescriptor(); |
| 90 } | 91 } |
| 91 return; | 92 return; |
| 92 } | 93 } |
| 93 if (!has_report_id_) { | 94 if (!has_report_id_) { |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 device_file_.GetPlatformFile(), HIDIOCSFEATURE(size), buffer, | 206 device_file_.GetPlatformFile(), HIDIOCSFEATURE(size), buffer, |
| 206 base::Bind(&HidConnectionLinux::FinishSendFeatureReport, | 207 base::Bind(&HidConnectionLinux::FinishSendFeatureReport, |
| 207 weak_factory_.GetWeakPtr(), callback), | 208 weak_factory_.GetWeakPtr(), callback), |
| 208 task_runner_)); | 209 task_runner_)); |
| 209 } | 210 } |
| 210 | 211 |
| 211 void HidConnectionLinux::FinishWrite(size_t expected_size, | 212 void HidConnectionLinux::FinishWrite(size_t expected_size, |
| 212 const WriteCallback& callback, | 213 const WriteCallback& callback, |
| 213 ssize_t result) { | 214 ssize_t result) { |
| 214 if (result < 0) { | 215 if (result < 0) { |
| 215 VPLOG(1) << "Write failed"; | 216 HID_PLOG(EVENT) << "Write failed"; |
| 216 callback.Run(false); | 217 callback.Run(false); |
| 217 } else { | 218 } else { |
| 218 if (static_cast<size_t>(result) != expected_size) { | 219 if (static_cast<size_t>(result) != expected_size) { |
| 219 LOG(WARNING) << "Incomplete HID write: " << result | 220 HID_LOG(EVENT) << "Incomplete HID write: " << result |
| 220 << " != " << expected_size; | 221 << " != " << expected_size; |
| 221 } | 222 } |
| 222 callback.Run(true); | 223 callback.Run(true); |
| 223 } | 224 } |
| 224 } | 225 } |
| 225 | 226 |
| 226 void HidConnectionLinux::FinishGetFeatureReport( | 227 void HidConnectionLinux::FinishGetFeatureReport( |
| 227 uint8_t report_id, | 228 uint8_t report_id, |
| 228 scoped_refptr<net::IOBuffer> buffer, | 229 scoped_refptr<net::IOBuffer> buffer, |
| 229 const ReadCallback& callback, | 230 const ReadCallback& callback, |
| 230 int result) { | 231 int result) { |
| 231 if (result < 0) { | 232 if (result < 0) { |
| 232 VPLOG(1) << "Failed to get feature report"; | 233 HID_PLOG(EVENT) << "Failed to get feature report"; |
| 233 callback.Run(false, NULL, 0); | 234 callback.Run(false, NULL, 0); |
| 234 } else if (result == 0) { | 235 } else if (result == 0) { |
| 235 VLOG(1) << "Get feature result too short."; | 236 HID_LOG(EVENT) << "Get feature result too short."; |
| 236 callback.Run(false, NULL, 0); | 237 callback.Run(false, NULL, 0); |
| 237 } else if (report_id == 0) { | 238 } else if (report_id == 0) { |
| 238 // Linux adds a 0 to the beginning of the data received from the device. | 239 // Linux adds a 0 to the beginning of the data received from the device. |
| 239 scoped_refptr<net::IOBuffer> copied_buffer(new net::IOBuffer(result - 1)); | 240 scoped_refptr<net::IOBuffer> copied_buffer(new net::IOBuffer(result - 1)); |
| 240 memcpy(copied_buffer->data(), buffer->data() + 1, result - 1); | 241 memcpy(copied_buffer->data(), buffer->data() + 1, result - 1); |
| 241 callback.Run(true, copied_buffer, result - 1); | 242 callback.Run(true, copied_buffer, result - 1); |
| 242 } else { | 243 } else { |
| 243 callback.Run(true, buffer, result); | 244 callback.Run(true, buffer, result); |
| 244 } | 245 } |
| 245 } | 246 } |
| 246 | 247 |
| 247 void HidConnectionLinux::FinishSendFeatureReport(const WriteCallback& callback, | 248 void HidConnectionLinux::FinishSendFeatureReport(const WriteCallback& callback, |
| 248 int result) { | 249 int result) { |
| 249 if (result < 0) { | 250 if (result < 0) { |
| 250 VPLOG(1) << "Failed to send feature report"; | 251 HID_PLOG(EVENT) << "Failed to send feature report"; |
| 251 callback.Run(false); | 252 callback.Run(false); |
| 252 } else { | 253 } else { |
| 253 callback.Run(true); | 254 callback.Run(true); |
| 254 } | 255 } |
| 255 } | 256 } |
| 256 | 257 |
| 257 // static | 258 // static |
| 258 void HidConnectionLinux::BlockingWrite( | 259 void HidConnectionLinux::BlockingWrite( |
| 259 base::PlatformFile platform_file, | 260 base::PlatformFile platform_file, |
| 260 scoped_refptr<net::IOBuffer> buffer, | 261 scoped_refptr<net::IOBuffer> buffer, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 PendingHidReport report = pending_reports_.front(); | 301 PendingHidReport report = pending_reports_.front(); |
| 301 | 302 |
| 302 pending_reports_.pop(); | 303 pending_reports_.pop(); |
| 303 if (CompleteRead(report.buffer, report.size, read.callback)) { | 304 if (CompleteRead(report.buffer, report.size, read.callback)) { |
| 304 pending_reads_.pop(); | 305 pending_reads_.pop(); |
| 305 } | 306 } |
| 306 } | 307 } |
| 307 } | 308 } |
| 308 | 309 |
| 309 } // namespace device | 310 } // namespace device |
| OLD | NEW |