Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: device/hid/hid_connection_linux.cc

Issue 499713002: Don't pass buffers to HidConnection::Read because it knows the size. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed rockot@'s nits. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « device/hid/hid_connection_linux.h ('k') | device/hid/hid_connection_mac.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <fcntl.h> 8 #include <fcntl.h>
9 #include <libudev.h> 9 #include <libudev.h>
10 #include <linux/hidraw.h> 10 #include <linux/hidraw.h>
(...skipping 11 matching lines...) Expand all
22 // These are already defined in newer versions of linux/hidraw.h. 22 // These are already defined in newer versions of linux/hidraw.h.
23 #ifndef HIDIOCSFEATURE 23 #ifndef HIDIOCSFEATURE
24 #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x06, len) 24 #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x06, len)
25 #endif 25 #endif
26 #ifndef HIDIOCGFEATURE 26 #ifndef HIDIOCGFEATURE
27 #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x07, len) 27 #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE | _IOC_READ, 'H', 0x07, len)
28 #endif 28 #endif
29 29
30 namespace device { 30 namespace device {
31 31
32 namespace {
33
34 // Copies a buffer into a new one with a report ID byte inserted at the front.
35 scoped_refptr<net::IOBufferWithSize> CopyBufferWithReportId(
36 scoped_refptr<net::IOBufferWithSize> buffer,
37 uint8_t report_id) {
38 scoped_refptr<net::IOBufferWithSize> new_buffer(
39 new net::IOBufferWithSize(buffer->size() + 1));
40 new_buffer->data()[0] = report_id;
41 memcpy(new_buffer->data() + 1, buffer->data(), buffer->size());
42 return new_buffer;
43 }
44
45 } // namespace
46
47 HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info, 32 HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info,
48 std::string dev_node) 33 std::string dev_node)
49 : HidConnection(device_info) { 34 : HidConnection(device_info) {
50 int flags = base::File::FLAG_OPEN | 35 int flags = base::File::FLAG_OPEN |
51 base::File::FLAG_READ | 36 base::File::FLAG_READ |
52 base::File::FLAG_WRITE; 37 base::File::FLAG_WRITE;
53 38
54 base::File device_file(base::FilePath(dev_node), flags); 39 base::File device_file(base::FilePath(dev_node), flags);
55 if (!device_file.IsValid()) { 40 if (!device_file.IsValid()) {
56 base::File::Error file_error = device_file.error_details(); 41 base::File::Error file_error = device_file.error_details();
(...skipping 27 matching lines...) Expand all
84 this)) { 69 this)) {
85 LOG(ERROR) << "Failed to start watching device file."; 70 LOG(ERROR) << "Failed to start watching device file.";
86 } 71 }
87 } 72 }
88 73
89 HidConnectionLinux::~HidConnectionLinux() { 74 HidConnectionLinux::~HidConnectionLinux() {
90 Disconnect(); 75 Disconnect();
91 Flush(); 76 Flush();
92 } 77 }
93 78
94 void HidConnectionLinux::PlatformRead( 79 void HidConnectionLinux::PlatformRead(const ReadCallback& callback) {
95 scoped_refptr<net::IOBufferWithSize> buffer,
96 const IOCallback& callback) {
97 PendingHidRead pending_read; 80 PendingHidRead pending_read;
98 pending_read.buffer = buffer;
99 pending_read.callback = callback; 81 pending_read.callback = callback;
100 pending_reads_.push(pending_read); 82 pending_reads_.push(pending_read);
101 ProcessReadQueue(); 83 ProcessReadQueue();
102 } 84 }
103 85
104 void HidConnectionLinux::PlatformWrite( 86 void HidConnectionLinux::PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
105 uint8_t report_id, 87 size_t size,
106 scoped_refptr<net::IOBufferWithSize> buffer, 88 const WriteCallback& callback) {
107 const IOCallback& callback) { 89 // Linux expects the first byte of the buffer to always be a report ID so the
108 // Linux always expects the first byte of the buffer to be the report ID. 90 // buffer can be used directly.
109 buffer = CopyBufferWithReportId(buffer, report_id); 91 const ssize_t bytes_written =
110 const int bytes_written = HANDLE_EINTR( 92 HANDLE_EINTR(write(device_file_.GetPlatformFile(), buffer->data(), size));
111 write(device_file_.GetPlatformFile(), buffer->data(), buffer->size()));
112 if (bytes_written < 0) { 93 if (bytes_written < 0) {
113 VPLOG(1) << "Write failed"; 94 VPLOG(1) << "Write failed";
114 Disconnect(); 95 Disconnect();
115 callback.Run(false, 0); 96 callback.Run(false);
116 } else { 97 } else {
117 if (bytes_written != buffer->size()) { 98 if (static_cast<size_t>(bytes_written) != size) {
118 LOG(WARNING) << "Incomplete HID write: " 99 LOG(WARNING) << "Incomplete HID write: " << bytes_written
119 << bytes_written << " != " << buffer->size(); 100 << " != " << size;
120 } 101 }
121 callback.Run(true, bytes_written == 0 ? 0 : bytes_written - 1); 102 callback.Run(true);
122 } 103 }
123 } 104 }
124 105
125 void HidConnectionLinux::PlatformGetFeatureReport( 106 void HidConnectionLinux::PlatformGetFeatureReport(
126 uint8_t report_id, 107 uint8_t report_id,
127 scoped_refptr<net::IOBufferWithSize> buffer, 108 const ReadCallback& callback) {
128 const IOCallback& callback) { 109 // The first byte of the destination buffer is the report ID being requested
129 if (buffer->size() == 0) { 110 // and is overwritten by the feature report.
130 callback.Run(false, 0); 111 DCHECK_GT(device_info().max_feature_report_size, 0);
131 return; 112 scoped_refptr<net::IOBufferWithSize> buffer(
132 } 113 new net::IOBufferWithSize(device_info().max_feature_report_size));
114 buffer->data()[0] = report_id;
133 115
134 // The first byte of the destination buffer is the report ID being requested.
135 buffer->data()[0] = report_id;
136 int result = ioctl(device_file_.GetPlatformFile(), 116 int result = ioctl(device_file_.GetPlatformFile(),
137 HIDIOCGFEATURE(buffer->size()), 117 HIDIOCGFEATURE(buffer->size()),
138 buffer->data()); 118 buffer->data());
139 if (result < 0) { 119 if (result < 0) {
140 VPLOG(1) << "Failed to get feature report"; 120 VPLOG(1) << "Failed to get feature report";
141 callback.Run(false, 0); 121 callback.Run(false, NULL, 0);
142 } else { 122 } else {
143 callback.Run(true, result); 123 callback.Run(true, buffer, result);
144 } 124 }
145 } 125 }
146 126
147 void HidConnectionLinux::PlatformSendFeatureReport( 127 void HidConnectionLinux::PlatformSendFeatureReport(
148 uint8_t report_id, 128 scoped_refptr<net::IOBuffer> buffer,
149 scoped_refptr<net::IOBufferWithSize> buffer, 129 size_t size,
150 const IOCallback& callback) { 130 const WriteCallback& callback) {
151 if (report_id != 0) 131 // Linux expects the first byte of the buffer to always be a report ID so the
152 buffer = CopyBufferWithReportId(buffer, report_id); 132 // buffer can be used directly.
153 int result = ioctl(device_file_.GetPlatformFile(), 133 int result = ioctl(
154 HIDIOCSFEATURE(buffer->size()), 134 device_file_.GetPlatformFile(), HIDIOCSFEATURE(size), buffer->data());
155 buffer->data());
156 if (result < 0) { 135 if (result < 0) {
157 VPLOG(1) << "Failed to send feature report"; 136 VPLOG(1) << "Failed to send feature report";
158 callback.Run(false, 0); 137 callback.Run(false);
159 } else { 138 } else {
160 callback.Run(true, result); 139 callback.Run(true);
161 } 140 }
162 } 141 }
163 142
164 void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) { 143 void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) {
165 DCHECK(thread_checker().CalledOnValidThread()); 144 DCHECK(thread_checker().CalledOnValidThread());
166 DCHECK_EQ(fd, device_file_.GetPlatformFile()); 145 DCHECK_EQ(fd, device_file_.GetPlatformFile());
167 146
168 uint8 raw_buffer[1024] = {0}; 147 size_t expected_report_size = device_info().max_input_report_size + 1;
169 int bytes_read = 148 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(expected_report_size));
170 HANDLE_EINTR(read(device_file_.GetPlatformFile(), raw_buffer, 1024)); 149 char* data = buffer->data();
150 if (!device_info().has_report_id) {
151 // Linux will not prefix the buffer with a report ID if they are not used
152 // by the device.
153 data[0] = 0;
154 data++;
155 expected_report_size--;
156 }
157
158 ssize_t bytes_read = HANDLE_EINTR(
159 read(device_file_.GetPlatformFile(), data, expected_report_size));
171 if (bytes_read < 0) { 160 if (bytes_read < 0) {
172 if (errno == EAGAIN) { 161 if (errno == EAGAIN) {
173 return; 162 return;
174 } 163 }
175 VPLOG(1) << "Read failed"; 164 VPLOG(1) << "Read failed";
176 Disconnect(); 165 Disconnect();
177 return; 166 return;
178 } 167 }
168 if (!device_info().has_report_id) {
169 // Include the byte prepended earlier.
170 bytes_read++;
171 }
179 172
180 scoped_refptr<net::IOBufferWithSize> buffer = 173 ProcessInputReport(buffer, bytes_read);
181 new net::IOBufferWithSize(bytes_read);
182 memcpy(buffer->data(), raw_buffer, bytes_read);
183
184 ProcessInputReport(buffer);
185 } 174 }
186 175
187 void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) { 176 void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) {
188 } 177 }
189 178
190 void HidConnectionLinux::Disconnect() { 179 void HidConnectionLinux::Disconnect() {
191 DCHECK(thread_checker().CalledOnValidThread()); 180 DCHECK(thread_checker().CalledOnValidThread());
192 device_file_watcher_.StopWatchingFileDescriptor(); 181 device_file_watcher_.StopWatchingFileDescriptor();
193 device_file_.Close(); 182 device_file_.Close();
194 183
195 Flush(); 184 Flush();
196 } 185 }
197 186
198 void HidConnectionLinux::Flush() { 187 void HidConnectionLinux::Flush() {
199 while (!pending_reads_.empty()) { 188 while (!pending_reads_.empty()) {
200 pending_reads_.front().callback.Run(false, 0); 189 pending_reads_.front().callback.Run(false, NULL, 0);
201 pending_reads_.pop(); 190 pending_reads_.pop();
202 } 191 }
203 } 192 }
204 193
205 void HidConnectionLinux::ProcessInputReport( 194 void HidConnectionLinux::ProcessInputReport(scoped_refptr<net::IOBuffer> buffer,
206 scoped_refptr<net::IOBufferWithSize> buffer) { 195 size_t size) {
207 DCHECK(thread_checker().CalledOnValidThread()); 196 DCHECK(thread_checker().CalledOnValidThread());
208 PendingHidReport report; 197 PendingHidReport report;
209 report.buffer = buffer; 198 report.buffer = buffer;
199 report.size = size;
210 pending_reports_.push(report); 200 pending_reports_.push(report);
211 ProcessReadQueue(); 201 ProcessReadQueue();
212 } 202 }
213 203
214 void HidConnectionLinux::ProcessReadQueue() { 204 void HidConnectionLinux::ProcessReadQueue() {
215 DCHECK(thread_checker().CalledOnValidThread()); 205 DCHECK(thread_checker().CalledOnValidThread());
216 while (pending_reads_.size() && pending_reports_.size()) { 206 while (pending_reads_.size() && pending_reports_.size()) {
217 PendingHidRead read = pending_reads_.front(); 207 PendingHidRead read = pending_reads_.front();
218 PendingHidReport report = pending_reports_.front(); 208 PendingHidReport report = pending_reports_.front();
219 209
220 if (read.buffer->size() < report.buffer->size()) { 210 pending_reports_.pop();
221 read.callback.Run(false, 0); 211 if (CompleteRead(report.buffer, report.size, read.callback)) {
222 pending_reads_.pop(); 212 pending_reads_.pop();
223 } else {
224 memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
225 pending_reports_.pop();
226
227 if (CompleteRead(read.buffer, report.buffer->size(), read.callback)) {
228 pending_reads_.pop();
229 }
230 } 213 }
231 } 214 }
232 } 215 }
233 216
234 } // namespace device 217 } // namespace device
OLDNEW
« no previous file with comments | « device/hid/hid_connection_linux.h ('k') | device/hid/hid_connection_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698