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 |