Chromium Code Reviews| 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.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 |
| OLD | NEW |