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.
5 #include "device/devices_app/usb/device_impl.h"
8 #include "base/callback.h"
9 #include "base/stl_util.h"
10 #include "device/devices_app/usb/type_converters.h"
11 #include "device/usb/usb_descriptors.h"
12 #include "device/usb/usb_device.h"
13 #include "net/base/io_buffer.h"
20 template <typename
... Args
>
21 void CallMojoCallback(const mojo::Callback
<void(Args
...)>& callback
,
23 callback
.Run(args
...);
26 // Generic wrapper to convert a Mojo callback to something we can rebind and
27 // pass around. This is only usable for callbacks with no move-only arguments.
28 template <typename
... Args
>
29 base::Callback
<void(Args
...)> WrapMojoCallback(
30 const mojo::Callback
<void(Args
...)>& callback
) {
31 return base::Bind(&CallMojoCallback
<Args
...>, callback
);
34 scoped_refptr
<net::IOBuffer
> CreateTransferBuffer(size_t size
) {
35 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(
36 std::max(static_cast<size_t>(1u), static_cast<size_t>(size
)));
42 DeviceImpl::DeviceImpl(scoped_refptr
<UsbDeviceHandle
> device_handle
,
43 mojo::InterfaceRequest
<Device
> request
)
44 : binding_(this, request
.Pass()),
45 device_handle_(device_handle
),
49 DeviceImpl::~DeviceImpl() {
53 void DeviceImpl::CloseHandle() {
55 device_handle_
->Close();
56 device_handle_
= nullptr;
59 void DeviceImpl::OnTransferIn(const MojoTransferInCallback
& callback
,
60 UsbTransferStatus status
,
61 scoped_refptr
<net::IOBuffer
> buffer
,
63 mojo::Array
<uint8_t> data
;
65 // TODO(rockot/reillyg): We should change UsbDeviceHandle to use a
66 // std::vector<uint8_t> instead of net::IOBuffer. Then we could move
68 std::vector
<uint8_t> bytes(buffer_size
);
69 std::copy(buffer
->data(), buffer
->data() + buffer_size
, bytes
.begin());
72 callback
.Run(mojo::ConvertTo
<TransferStatus
>(status
), data
.Pass());
75 void DeviceImpl::OnTransferOut(const MojoTransferOutCallback
& callback
,
76 UsbTransferStatus status
,
77 scoped_refptr
<net::IOBuffer
> buffer
,
79 callback
.Run(mojo::ConvertTo
<TransferStatus
>(status
));
82 void DeviceImpl::OnIsochronousTransferIn(
83 const IsochronousTransferInCallback
& callback
,
85 UsbTransferStatus status
,
86 scoped_refptr
<net::IOBuffer
> buffer
,
88 size_t num_packets
= buffer_size
/ packet_size
;
89 mojo::Array
<mojo::Array
<uint8_t>> packets(num_packets
);
91 for (size_t i
= 0; i
< num_packets
; ++i
) {
92 size_t packet_index
= i
* packet_size
;
93 std::vector
<uint8_t> bytes(packet_size
);
94 std::copy(buffer
->data() + packet_index
,
95 buffer
->data() + packet_index
+ packet_size
, bytes
.begin());
96 packets
[i
].Swap(&bytes
);
99 callback
.Run(mojo::ConvertTo
<TransferStatus
>(status
), packets
.Pass());
102 void DeviceImpl::OnIsochronousTransferOut(
103 const MojoTransferOutCallback
& callback
,
104 UsbTransferStatus status
,
105 scoped_refptr
<net::IOBuffer
> buffer
,
106 size_t buffer_size
) {
107 callback
.Run(mojo::ConvertTo
<TransferStatus
>(status
));
110 void DeviceImpl::Close(const CloseCallback
& callback
) {
115 void DeviceImpl::GetDeviceInfo(const GetDeviceInfoCallback
& callback
) {
116 if (!device_handle_
) {
117 callback
.Run(DeviceInfoPtr());
121 // TODO(rockot/reillyg): Converting configuration info should be done in the
122 // TypeConverter, but GetConfiguration() is non-const so we do it here for
124 DeviceInfoPtr info
= DeviceInfo::From(*device_handle_
->GetDevice());
125 const std::vector
<UsbConfigDescriptor
>& configs
=
126 device_handle_
->GetDevice()->configurations();
127 info
->configurations
= mojo::Array
<ConfigurationInfoPtr
>::New(configs
.size());
128 for (size_t i
= 0; i
< configs
.size(); ++i
) {
129 info
->configurations
[i
] = ConfigurationInfo::From(configs
[i
]);
131 callback
.Run(info
.Pass());
134 void DeviceImpl::SetConfiguration(uint8_t value
,
135 const SetConfigurationCallback
& callback
) {
136 if (!device_handle_
) {
141 device_handle_
->SetConfiguration(value
, WrapMojoCallback(callback
));
144 void DeviceImpl::ClaimInterface(uint8_t interface_number
,
145 const ClaimInterfaceCallback
& callback
) {
146 if (!device_handle_
) {
151 device_handle_
->ClaimInterface(interface_number
, WrapMojoCallback(callback
));
154 void DeviceImpl::ReleaseInterface(uint8_t interface_number
,
155 const ReleaseInterfaceCallback
& callback
) {
156 if (!device_handle_
) {
161 callback
.Run(device_handle_
->ReleaseInterface(interface_number
));
164 void DeviceImpl::SetInterfaceAlternateSetting(
165 uint8_t interface_number
,
166 uint8_t alternate_setting
,
167 const SetInterfaceAlternateSettingCallback
& callback
) {
168 if (!device_handle_
) {
173 device_handle_
->SetInterfaceAlternateSetting(
174 interface_number
, alternate_setting
, WrapMojoCallback(callback
));
177 void DeviceImpl::Reset(const ResetCallback
& callback
) {
178 if (!device_handle_
) {
183 device_handle_
->ResetDevice(WrapMojoCallback(callback
));
186 void DeviceImpl::ClearHalt(uint8_t endpoint
,
187 const ClearHaltCallback
& callback
) {
188 if (!device_handle_
) {
193 device_handle_
->ClearHalt(endpoint
, WrapMojoCallback(callback
));
196 void DeviceImpl::ControlTransferIn(ControlTransferParamsPtr params
,
199 const ControlTransferInCallback
& callback
) {
200 if (!device_handle_
) {
201 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<uint8_t>());
205 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(length
);
206 device_handle_
->ControlTransfer(
207 USB_DIRECTION_INBOUND
,
208 mojo::ConvertTo
<UsbDeviceHandle::TransferRequestType
>(params
->type
),
209 mojo::ConvertTo
<UsbDeviceHandle::TransferRecipient
>(params
->recipient
),
210 params
->request
, params
->value
, params
->index
, buffer
, length
, timeout
,
211 base::Bind(&DeviceImpl::OnTransferIn
, weak_factory_
.GetWeakPtr(),
215 void DeviceImpl::ControlTransferOut(
216 ControlTransferParamsPtr params
,
217 mojo::Array
<uint8_t> data
,
219 const ControlTransferOutCallback
& callback
) {
220 if (!device_handle_
) {
221 callback
.Run(TRANSFER_STATUS_ERROR
);
225 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(data
.size());
226 const std::vector
<uint8_t>& storage
= data
.storage();
227 std::copy(storage
.begin(), storage
.end(), buffer
->data());
228 device_handle_
->ControlTransfer(
229 USB_DIRECTION_OUTBOUND
,
230 mojo::ConvertTo
<UsbDeviceHandle::TransferRequestType
>(params
->type
),
231 mojo::ConvertTo
<UsbDeviceHandle::TransferRecipient
>(params
->recipient
),
232 params
->request
, params
->value
, params
->index
, buffer
, data
.size(),
233 timeout
, base::Bind(&DeviceImpl::OnTransferOut
,
234 weak_factory_
.GetWeakPtr(), callback
));
237 void DeviceImpl::BulkTransferIn(uint8_t endpoint_number
,
240 const BulkTransferInCallback
& callback
) {
241 if (!device_handle_
) {
242 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<uint8_t>());
246 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(length
);
247 device_handle_
->BulkTransfer(
248 USB_DIRECTION_INBOUND
, endpoint_number
, buffer
, length
, timeout
,
249 base::Bind(&DeviceImpl::OnTransferIn
, weak_factory_
.GetWeakPtr(),
253 void DeviceImpl::BulkTransferOut(uint8_t endpoint_number
,
254 mojo::Array
<uint8_t> data
,
256 const BulkTransferOutCallback
& callback
) {
257 if (!device_handle_
) {
258 callback
.Run(TRANSFER_STATUS_ERROR
);
262 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(data
.size());
263 const std::vector
<uint8_t>& storage
= data
.storage();
264 std::copy(storage
.begin(), storage
.end(), buffer
->data());
265 device_handle_
->BulkTransfer(
266 USB_DIRECTION_OUTBOUND
, endpoint_number
, buffer
, data
.size(), timeout
,
267 base::Bind(&DeviceImpl::OnTransferOut
, weak_factory_
.GetWeakPtr(),
271 void DeviceImpl::InterruptTransferIn(
272 uint8_t endpoint_number
,
275 const InterruptTransferInCallback
& callback
) {
276 if (!device_handle_
) {
277 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<uint8_t>());
281 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(length
);
282 device_handle_
->InterruptTransfer(
283 USB_DIRECTION_INBOUND
, endpoint_number
, buffer
, length
, timeout
,
284 base::Bind(&DeviceImpl::OnTransferIn
, weak_factory_
.GetWeakPtr(),
288 void DeviceImpl::InterruptTransferOut(
289 uint8_t endpoint_number
,
290 mojo::Array
<uint8_t> data
,
292 const InterruptTransferOutCallback
& callback
) {
293 if (!device_handle_
) {
294 callback
.Run(TRANSFER_STATUS_ERROR
);
298 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(data
.size());
299 const std::vector
<uint8_t>& storage
= data
.storage();
300 std::copy(storage
.begin(), storage
.end(), buffer
->data());
301 device_handle_
->InterruptTransfer(
302 USB_DIRECTION_OUTBOUND
, endpoint_number
, buffer
, data
.size(), timeout
,
303 base::Bind(&DeviceImpl::OnTransferOut
, weak_factory_
.GetWeakPtr(),
307 void DeviceImpl::IsochronousTransferIn(
308 uint8_t endpoint_number
,
309 uint32_t num_packets
,
310 uint32_t packet_length
,
312 const IsochronousTransferInCallback
& callback
) {
313 if (!device_handle_
) {
314 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<mojo::Array
<uint8_t>>());
318 size_t transfer_size
= static_cast<size_t>(num_packets
) * packet_length
;
319 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(transfer_size
);
320 device_handle_
->IsochronousTransfer(
321 USB_DIRECTION_INBOUND
, endpoint_number
, buffer
, transfer_size
,
322 num_packets
, packet_length
, timeout
,
323 base::Bind(&DeviceImpl::OnIsochronousTransferIn
,
324 weak_factory_
.GetWeakPtr(), callback
, packet_length
));
327 void DeviceImpl::IsochronousTransferOut(
328 uint8_t endpoint_number
,
329 mojo::Array
<mojo::Array
<uint8_t>> packets
,
331 const IsochronousTransferOutCallback
& callback
) {
332 if (!device_handle_
) {
333 callback
.Run(TRANSFER_STATUS_ERROR
);
337 uint32_t packet_size
= 0;
338 for (size_t i
= 0; i
< packets
.size(); ++i
) {
340 std::max(packet_size
, static_cast<uint32_t>(packets
[i
].size()));
342 size_t transfer_size
= packet_size
* packets
.size();
343 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(transfer_size
);
344 memset(buffer
->data(), 0, transfer_size
);
345 for (size_t i
= 0; i
< packets
.size(); ++i
) {
347 reinterpret_cast<uint8_t*>(&buffer
->data()[i
* packet_size
]);
348 DCHECK_LE(packets
[i
].size(), static_cast<size_t>(packet_size
));
349 memcpy(packet
, packets
[i
].storage().data(), packets
[i
].size());
351 device_handle_
->IsochronousTransfer(
352 USB_DIRECTION_OUTBOUND
, endpoint_number
, buffer
, transfer_size
,
353 static_cast<uint32_t>(packets
.size()), packet_size
, timeout
,
354 base::Bind(&DeviceImpl::OnIsochronousTransferOut
,
355 weak_factory_
.GetWeakPtr(), callback
));
359 } // namespace device