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

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

Issue 317783010: chrome.hid: enrich model with report IDs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Filter reports + refactor HID connections (ongoing) Created 6 years, 6 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
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.h" 5 #include "device/hid/hid_connection.h"
6 6
7 #include <algorithm>
8
7 namespace device { 9 namespace device {
8 10
11 namespace {
12
13 const uint8_t kNullReportId = 0x00;
14 const uint8_t kInvalidReportId = 0xFF;
Ken Rockot(use gerrit already) 2014/06/19 19:29:56 Shouldn't this be kAnyReportId given the usage?
jracle (use Gerrit) 2014/06/19 21:39:36 Right, that's indeed what it means. On 2014/06/19
15
16 struct CollectionHasReportId {
17 explicit CollectionHasReportId(const uint8_t report_id)
18 : report_id_(report_id) {}
19
20 bool operator()(const HidCollectionInfo& info) const {
21 if (info.report_ids.size() == 0 || report_id_ == kNullReportId)
22 return false;
23
24 if (report_id_ == kInvalidReportId)
25 return true;
26
27 return std::find(info.report_ids.begin(),
28 info.report_ids.end(),
29 report_id_) != info.report_ids.end();
30 }
31
32 private:
33 const uint8_t report_id_;
34 };
35
36 struct CollectionIsProtected {
37 bool operator()(const HidCollectionInfo& info) const {
38 return info.usage.IsProtected();
39 }
40 };
41
42 bool HasReportId(const HidDeviceInfo& device_info,
Ken Rockot(use gerrit already) 2014/06/19 19:29:56 This doesn't quite do what the name implies. How a
jracle (use Gerrit) 2014/06/19 21:39:36 Thanks so much for noticing it! See, indeed defau
43 const uint8_t report_id = kInvalidReportId,
44 HidCollectionInfo* collection_info = NULL) {
45 std::vector<HidCollectionInfo>::const_iterator collection_iter =
46 std::find_if(device_info.collections.begin(),
47 device_info.collections.end(),
48 CollectionHasReportId(report_id));
49 if (collection_iter != device_info.collections.end()) {
50 if (collection_info) {
51 *collection_info = *collection_iter;
52 }
53 return true;
54 }
55
56 return false;
57 }
58
59 bool HasProtectedCollection(const HidDeviceInfo& device_info) {
60 return std::find_if(device_info.collections.begin(),
61 device_info.collections.end(),
62 CollectionIsProtected()) != device_info.collections.end();
63 }
64
65 } // namespace
66
67 HidConnection::HidConnection(const HidDeviceInfo& device_info)
68 : device_info_(device_info) {
69 DCHECK(thread_checker_.CalledOnValidThread());
70 has_protected_collection_ = HasProtectedCollection(device_info);
71 has_report_id_ = HasReportId(device_info);
jracle (use Gerrit) 2014/06/11 11:20:04 I prefer to cache this info..
Ken Rockot(use gerrit already) 2014/06/19 19:29:56 Sure, sounds fine to me.
jracle (use Gerrit) 2014/06/19 21:39:36 Thx. On 2014/06/19 19:29:56, Ken Rockot wrote:
72 }
73
74 HidConnection::~HidConnection() {
75 DCHECK(thread_checker_.CalledOnValidThread());
76 }
77
78 void HidConnection::Read(scoped_refptr<net::IOBufferWithSize> buffer,
79 const IOCallback& callback) {
80 DCHECK(thread_checker_.CalledOnValidThread());
81 if (device_info_.max_input_report_size == 0) {
82 // The device does not support input reports.
83 callback.Run(false, 0);
84 return;
85 }
86 int expected_buffer_size = device_info_.max_input_report_size;
87 if (!has_report_id()) {
88 expected_buffer_size--;
89 }
90 if (buffer->size() < expected_buffer_size) {
91 // Receive buffer is too small.
92 callback.Run(false, 0);
93 return;
94 }
95
96 PlatformRead(buffer, callback);
97 }
98
99 void HidConnection::Write(uint8_t report_id,
100 scoped_refptr<net::IOBufferWithSize> buffer,
101 const IOCallback& callback) {
102 DCHECK(thread_checker_.CalledOnValidThread());
103 if (device_info_.max_output_report_size == 0) {
104 // The device does not support output reports.
105 callback.Run(false, 0);
106 return;
107 }
108 if (IsReportIdProtected(report_id)) {
jracle (use Gerrit) 2014/06/11 11:20:04 We need to prevent R/W of protected reports.
109 callback.Run(false, 0);
110 return;
111 }
112
113 PlatformWrite(report_id, buffer, callback);
114 }
115
116 void HidConnection::GetFeatureReport(
117 uint8_t report_id,
118 scoped_refptr<net::IOBufferWithSize> buffer,
119 const IOCallback& callback) {
120 DCHECK(thread_checker_.CalledOnValidThread());
121 if (device_info_.max_feature_report_size == 0) {
122 // The device does not support feature reports.
123 callback.Run(false, 0);
124 return;
125 }
126 if (IsReportIdProtected(report_id)) {
127 callback.Run(false, 0);
128 return;
129 }
130 int expected_buffer_size = device_info_.max_feature_report_size;
131 if (!has_report_id()) {
132 expected_buffer_size--;
133 }
134 if (buffer->size() < expected_buffer_size) {
135 // Receive buffer is too small.
136 callback.Run(false, 0);
137 return;
138 }
139
140 PlatformGetFeatureReport(report_id, buffer, callback);
141 }
142
143 void HidConnection::SendFeatureReport(
144 uint8_t report_id,
145 scoped_refptr<net::IOBufferWithSize> buffer,
146 const IOCallback& callback) {
147 DCHECK(thread_checker_.CalledOnValidThread());
148 if (device_info_.max_feature_report_size == 0) {
149 // The device does not support feature reports.
150 callback.Run(false, 0);
151 return;
152 }
153 if (IsReportIdProtected(report_id)) {
154 callback.Run(false, 0);
155 return;
156 }
157
158 PlatformSendFeatureReport(report_id, buffer, callback);
159 }
160
161 bool HidConnection::FilterInputReport(
jracle (use Gerrit) 2014/06/11 11:20:04 This is new filtering method, used together with n
162 scoped_refptr<net::IOBufferWithSize> buffer,
163 const IOCallback& callback) {
164 if (buffer->size() == 0) {
165 return false;
166 }
167
168 if (IsReportIdProtected(buffer->data()[0])) {
169 callback.Run(true, 0);
170 return true;
171 }
172
173 return false;
174 }
175
176 bool HidConnection::IsReportIdProtected(const uint8_t report_id) {
177 HidCollectionInfo collection_info;
178 if (HasReportId(device_info_, report_id, &collection_info)) {
179 return collection_info.usage.IsProtected();
180 }
181
182 return has_protected_collection();
183 }
184
9 PendingHidReport::PendingHidReport() {} 185 PendingHidReport::PendingHidReport() {}
10 186
11 PendingHidReport::~PendingHidReport() {} 187 PendingHidReport::~PendingHidReport() {}
12 188
13 PendingHidRead::PendingHidRead() {} 189 PendingHidRead::PendingHidRead() {}
14 190
15 PendingHidRead::~PendingHidRead() {} 191 PendingHidRead::~PendingHidRead() {}
16 192
17 HidConnection::HidConnection(const HidDeviceInfo& device_info) 193 HidConnection2::HidConnection2(const HidDeviceInfo& device_info)
18 : device_info_(device_info) {} 194 : HidConnection(device_info) {
195 }
19 196
20 HidConnection::~HidConnection() {} 197 HidConnection2::~HidConnection2() {
198 Flush();
199 }
200
201 void HidConnection2::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
Ken Rockot(use gerrit already) 2014/06/19 19:29:56 Ah, I see why you created this temporary class now
jracle (use Gerrit) 2014/06/19 21:39:36 Yes sorry, this was to eliminate duplication. Hen
202 const IOCallback& callback) {
203 PendingHidRead pending_read;
204 pending_read.buffer = buffer;
205 pending_read.callback = callback;
206 pending_reads_.push(pending_read);
207 ProcessReadQueue();
208 }
209
210 void HidConnection2::ProcessInputReport(
211 scoped_refptr<net::IOBufferWithSize> buffer) {
212 DCHECK(thread_checker().CalledOnValidThread());
213 PendingHidReport report;
214 report.buffer = buffer;
215 pending_reports_.push(report);
216 ProcessReadQueue();
217 }
218
219 void HidConnection2::Flush() {
220 while (!pending_reads_.empty()) {
221 pending_reads_.front().callback.Run(false, 0);
222 pending_reads_.pop();
223 }
224 }
225
226 void HidConnection2::ProcessReadQueue() {
227 DCHECK(thread_checker().CalledOnValidThread());
228 while (pending_reads_.size() && pending_reports_.size()) {
229 PendingHidRead read = pending_reads_.front();
230 pending_reads_.pop();
231 PendingHidReport report = pending_reports_.front();
232
233 if (read.buffer->size() < report.buffer->size()) {
234 read.callback.Run(false, report.buffer->size());
235 } else {
236 memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
237 pending_reports_.pop();
238
239 if (FilterInputReport(report.buffer, read.callback)) {
240 return;
241 }
242
243 read.callback.Run(true, report.buffer->size());
244 }
245 }
246 }
21 247
22 } // namespace device 248 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698