OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/bind.h" | |
6 #include "base/callback.h" | |
7 #include "base/stl_util.h" | |
8 #include "device/usb/device_impl.h" | |
9 #include "device/usb/type_converters.h" | |
10 #include "device/usb/usb_descriptors.h" | |
11 #include "device/usb/usb_device.h" | |
12 #include "net/base/io_buffer.h" | |
13 | |
14 namespace device { | |
15 namespace usb { | |
16 | |
17 namespace { | |
18 | |
19 template <typename... Args> | |
20 void CallMojoCallback(const mojo::Callback<void(Args...)>& callback, | |
21 Args... args) { | |
22 callback.Run(args...); | |
23 } | |
24 | |
25 // Generic wrapper to convert a Mojo callback to something we can rebind and | |
26 // pass around. This is only usable for callbacks with no move-only arguments. | |
27 template <typename... Args> | |
28 base::Callback<void(Args...)> WrapMojoCallback( | |
29 const mojo::Callback<void(Args...)>& callback) { | |
30 return base::Bind(&CallMojoCallback<Args...>, callback); | |
31 } | |
32 | |
33 scoped_refptr<net::IOBuffer> CreateTransferBuffer(size_t size) { | |
34 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer( | |
35 std::max(static_cast<size_t>(1u), static_cast<size_t>(size))); | |
36 return buffer; | |
37 } | |
38 | |
39 } // namespace | |
40 | |
41 DeviceImpl::DeviceImpl(scoped_refptr<UsbDeviceHandle> device_handle, | |
42 mojo::InterfaceRequest<Device> request) | |
43 : binding_(this, request.Pass()), | |
44 device_handle_(device_handle), | |
45 weak_factory_(this) { | |
46 } | |
47 | |
48 DeviceImpl::~DeviceImpl() { | |
49 CloseHandle(); | |
50 } | |
51 | |
52 void DeviceImpl::CloseHandle() { | |
53 if (device_handle_) | |
54 device_handle_->Close(); | |
55 device_handle_ = nullptr; | |
56 } | |
57 | |
58 void DeviceImpl::OnTransferIn(const MojoTransferInCallback& callback, | |
59 UsbTransferStatus status, | |
60 scoped_refptr<net::IOBuffer> buffer, | |
61 size_t buffer_size) { | |
62 mojo::Array<uint8_t> data; | |
63 if (buffer) { | |
64 // TODO(rockot/reillyg): We should change UsbDeviceHandle to use a | |
65 // std::vector<uint8_t> instead of net::IOBuffer. Then we could move | |
66 // instead of copy. | |
67 std::vector<uint8_t> bytes(buffer_size); | |
68 std::copy(buffer->data(), buffer->data() + buffer_size, bytes.begin()); | |
69 data.Swap(&bytes); | |
70 } | |
71 callback.Run(mojo::ConvertTo<TransferStatus>(status), data.Pass()); | |
72 } | |
73 | |
74 void DeviceImpl::OnTransferOut(const MojoTransferOutCallback& callback, | |
75 UsbTransferStatus status, | |
76 scoped_refptr<net::IOBuffer> buffer, | |
77 size_t buffer_size) { | |
78 callback.Run(mojo::ConvertTo<TransferStatus>(status)); | |
79 } | |
80 | |
81 void DeviceImpl::OnIsochronousTransferIn( | |
82 const IsochronousTransferInCallback& callback, | |
83 uint32_t packet_size, | |
84 UsbTransferStatus status, | |
85 scoped_refptr<net::IOBuffer> buffer, | |
86 size_t buffer_size) { | |
87 size_t num_packets = buffer_size / packet_size; | |
88 mojo::Array<mojo::Array<uint8_t>> packets(num_packets); | |
89 if (buffer) { | |
90 for (size_t i = 0; i < num_packets; ++i) { | |
91 size_t packet_index = i * packet_size; | |
92 std::vector<uint8_t> bytes(packet_size); | |
93 std::copy(buffer->data() + packet_index, | |
94 buffer->data() + packet_index + packet_size, bytes.begin()); | |
95 packets[i].Swap(&bytes); | |
96 } | |
97 } | |
98 callback.Run(mojo::ConvertTo<TransferStatus>(status), packets.Pass()); | |
99 } | |
100 | |
101 void DeviceImpl::OnIsochronousTransferOut( | |
102 const MojoTransferOutCallback& callback, | |
103 UsbTransferStatus status, | |
104 scoped_refptr<net::IOBuffer> buffer, | |
105 size_t buffer_size) { | |
106 callback.Run(mojo::ConvertTo<TransferStatus>(status)); | |
107 } | |
108 | |
109 void DeviceImpl::Close(const CloseCallback& callback) { | |
110 CloseHandle(); | |
111 callback.Run(); | |
112 } | |
113 | |
114 void DeviceImpl::GetDeviceInfo(const GetDeviceInfoCallback& callback) { | |
115 if (!device_handle_) { | |
116 callback.Run(DeviceInfoPtr()); | |
117 return; | |
118 } | |
119 | |
120 // TODO(rockot/reillyg): Support more than just the current configuration. | |
121 // Also, converting configuration info should be done in the TypeConverter, | |
122 // but GetConfiguration() is non-const so we do it here for now. | |
123 DeviceInfoPtr info = DeviceInfo::From(*device_handle_->GetDevice()); | |
124 const UsbConfigDescriptor* config = | |
125 device_handle_->GetDevice()->GetConfiguration(); | |
126 info->configurations = mojo::Array<ConfigurationInfoPtr>::New(0); | |
127 if (config) | |
128 info->configurations.push_back(ConfigurationInfo::From(*config)); | |
129 callback.Run(info.Pass()); | |
130 } | |
131 | |
132 void DeviceImpl::SetConfiguration(uint8_t value, | |
133 const SetConfigurationCallback& callback) { | |
134 if (!device_handle_) { | |
135 callback.Run(false); | |
136 return; | |
137 } | |
138 | |
139 device_handle_->SetConfiguration(value, WrapMojoCallback(callback)); | |
140 } | |
141 | |
142 void DeviceImpl::ClaimInterface(uint8_t interface_number, | |
143 const ClaimInterfaceCallback& callback) { | |
144 if (!device_handle_) { | |
145 callback.Run(false); | |
146 return; | |
147 } | |
148 | |
149 device_handle_->ClaimInterface(interface_number, WrapMojoCallback(callback)); | |
150 } | |
151 | |
152 void DeviceImpl::ReleaseInterface(uint8_t interface_number, | |
153 const ReleaseInterfaceCallback& callback) { | |
154 if (!device_handle_) { | |
155 callback.Run(false); | |
156 return; | |
157 } | |
158 | |
159 callback.Run(device_handle_->ReleaseInterface(interface_number)); | |
160 } | |
161 | |
162 void DeviceImpl::SetInterfaceAlternateSetting( | |
163 uint8_t interface_number, | |
164 uint8_t alternate_setting, | |
165 const SetInterfaceAlternateSettingCallback& callback) { | |
166 if (!device_handle_) { | |
167 callback.Run(false); | |
168 return; | |
169 } | |
170 | |
171 device_handle_->SetInterfaceAlternateSetting( | |
172 interface_number, alternate_setting, WrapMojoCallback(callback)); | |
173 } | |
174 | |
175 void DeviceImpl::Reset(const ResetCallback& callback) { | |
176 if (!device_handle_) { | |
177 callback.Run(false); | |
178 return; | |
179 } | |
180 | |
181 device_handle_->ResetDevice(WrapMojoCallback(callback)); | |
182 } | |
183 | |
184 void DeviceImpl::ControlTransferIn(ControlTransferParamsPtr params, | |
185 uint32_t length, | |
186 uint32_t timeout, | |
187 const ControlTransferInCallback& callback) { | |
188 if (!device_handle_) { | |
189 callback.Run(TRANSFER_STATUS_ERROR, mojo::Array<uint8_t>()); | |
190 return; | |
191 } | |
192 | |
193 scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(length); | |
194 device_handle_->ControlTransfer( | |
195 USB_DIRECTION_INBOUND, | |
196 mojo::ConvertTo<UsbDeviceHandle::TransferRequestType>(params->type), | |
197 mojo::ConvertTo<UsbDeviceHandle::TransferRecipient>(params->recipient), | |
198 params->request, params->value, params->index, buffer, length, timeout, | |
199 base::Bind(&DeviceImpl::OnTransferIn, weak_factory_.GetWeakPtr(), | |
200 callback)); | |
201 } | |
202 | |
203 void DeviceImpl::ControlTransferOut( | |
204 ControlTransferParamsPtr params, | |
205 mojo::Array<uint8_t> data, | |
206 uint32_t timeout, | |
207 const ControlTransferOutCallback& callback) { | |
208 if (!device_handle_) { | |
209 callback.Run(TRANSFER_STATUS_ERROR); | |
210 return; | |
211 } | |
212 | |
213 scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(data.size()); | |
214 const std::vector<uint8_t>& storage = data.storage(); | |
215 std::copy(storage.begin(), storage.end(), buffer->data()); | |
216 device_handle_->ControlTransfer( | |
217 USB_DIRECTION_OUTBOUND, | |
218 mojo::ConvertTo<UsbDeviceHandle::TransferRequestType>(params->type), | |
219 mojo::ConvertTo<UsbDeviceHandle::TransferRecipient>(params->recipient), | |
220 params->request, params->value, params->index, buffer, data.size(), | |
221 timeout, base::Bind(&DeviceImpl::OnTransferOut, | |
222 weak_factory_.GetWeakPtr(), callback)); | |
223 } | |
224 | |
225 void DeviceImpl::BulkTransferIn(uint8_t endpoint_number, | |
226 uint32_t length, | |
227 uint32_t timeout, | |
228 const BulkTransferInCallback& callback) { | |
229 if (!device_handle_) { | |
230 callback.Run(TRANSFER_STATUS_ERROR, mojo::Array<uint8_t>()); | |
231 return; | |
232 } | |
233 | |
234 scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(length); | |
235 device_handle_->BulkTransfer( | |
236 USB_DIRECTION_INBOUND, endpoint_number, buffer, length, timeout, | |
237 base::Bind(&DeviceImpl::OnTransferIn, weak_factory_.GetWeakPtr(), | |
238 callback)); | |
239 } | |
240 | |
241 void DeviceImpl::BulkTransferOut(uint8_t endpoint_number, | |
242 mojo::Array<uint8_t> data, | |
243 uint32_t timeout, | |
244 const BulkTransferOutCallback& callback) { | |
245 if (!device_handle_) { | |
246 callback.Run(TRANSFER_STATUS_ERROR); | |
247 return; | |
248 } | |
249 | |
250 scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(data.size()); | |
251 const std::vector<uint8_t>& storage = data.storage(); | |
252 std::copy(storage.begin(), storage.end(), buffer->data()); | |
253 device_handle_->BulkTransfer( | |
254 USB_DIRECTION_OUTBOUND, endpoint_number, buffer, data.size(), timeout, | |
255 base::Bind(&DeviceImpl::OnTransferOut, weak_factory_.GetWeakPtr(), | |
256 callback)); | |
257 } | |
258 | |
259 void DeviceImpl::InterruptTransferIn( | |
260 uint8_t endpoint_number, | |
261 uint32_t length, | |
262 uint32_t timeout, | |
263 const InterruptTransferInCallback& callback) { | |
264 if (!device_handle_) { | |
265 callback.Run(TRANSFER_STATUS_ERROR, mojo::Array<uint8_t>()); | |
266 return; | |
267 } | |
268 | |
269 scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(length); | |
270 device_handle_->InterruptTransfer( | |
271 USB_DIRECTION_INBOUND, endpoint_number, buffer, length, timeout, | |
272 base::Bind(&DeviceImpl::OnTransferIn, weak_factory_.GetWeakPtr(), | |
273 callback)); | |
274 } | |
275 | |
276 void DeviceImpl::InterruptTransferOut( | |
277 uint8_t endpoint_number, | |
278 mojo::Array<uint8_t> data, | |
279 uint32_t timeout, | |
280 const InterruptTransferOutCallback& callback) { | |
281 if (!device_handle_) { | |
282 callback.Run(TRANSFER_STATUS_ERROR); | |
283 return; | |
284 } | |
285 | |
286 scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(data.size()); | |
287 const std::vector<uint8_t>& storage = data.storage(); | |
288 std::copy(storage.begin(), storage.end(), buffer->data()); | |
289 device_handle_->InterruptTransfer( | |
290 USB_DIRECTION_OUTBOUND, endpoint_number, buffer, data.size(), timeout, | |
291 base::Bind(&DeviceImpl::OnTransferOut, weak_factory_.GetWeakPtr(), | |
292 callback)); | |
293 } | |
294 | |
295 void DeviceImpl::IsochronousTransferIn( | |
296 uint8_t endpoint_number, | |
297 uint32_t num_packets, | |
298 uint32_t packet_length, | |
299 uint32_t timeout, | |
300 const IsochronousTransferInCallback& callback) { | |
301 if (!device_handle_) { | |
302 callback.Run(TRANSFER_STATUS_ERROR, mojo::Array<mojo::Array<uint8_t>>()); | |
303 return; | |
304 } | |
305 | |
306 size_t transfer_size = static_cast<size_t>(num_packets) * packet_length; | |
307 scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(transfer_size); | |
308 device_handle_->IsochronousTransfer( | |
309 USB_DIRECTION_INBOUND, endpoint_number, buffer, transfer_size, | |
310 num_packets, packet_length, timeout, | |
311 base::Bind(&DeviceImpl::OnIsochronousTransferIn, | |
312 weak_factory_.GetWeakPtr(), callback, packet_length)); | |
313 } | |
314 | |
315 void DeviceImpl::IsochronousTransferOut( | |
316 uint8_t endpoint_number, | |
317 mojo::Array<mojo::Array<uint8_t>> packets, | |
318 uint32_t timeout, | |
319 const IsochronousTransferOutCallback& callback) { | |
320 if (!device_handle_) { | |
321 callback.Run(TRANSFER_STATUS_ERROR); | |
322 return; | |
323 } | |
324 | |
325 uint32_t packet_size = 0; | |
326 for (size_t i = 0; i < packets.size(); ++i) { | |
327 packet_size = | |
328 std::max(packet_size, static_cast<uint32_t>(packets[i].size())); | |
329 } | |
330 size_t transfer_size = packet_size * packets.size(); | |
331 scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(transfer_size); | |
332 memset(buffer->data(), 0, transfer_size); | |
333 for (size_t i = 0; i < packets.size(); ++i) { | |
334 uint8_t* packet = | |
335 reinterpret_cast<uint8_t*>(&buffer->data()[i * packet_size]); | |
336 DCHECK_LE(packets[i].size(), static_cast<size_t>(packet_size)); | |
337 memcpy(packet, packets[i].storage().data(), packets[i].size()); | |
338 } | |
339 device_handle_->IsochronousTransfer( | |
340 USB_DIRECTION_OUTBOUND, endpoint_number, buffer, transfer_size, | |
341 static_cast<uint32_t>(packets.size()), packet_size, timeout, | |
342 base::Bind(&DeviceImpl::OnIsochronousTransferOut, | |
343 weak_factory_.GetWeakPtr(), callback)); | |
344 } | |
345 | |
346 } // namespace usb | |
347 } // namespace device | |
OLD | NEW |