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): Support more than just the current configuration.
122 // Also, converting configuration info should be done in the TypeConverter,
123 // but GetConfiguration() is non-const so we do it here for now.
124 DeviceInfoPtr info
= DeviceInfo::From(*device_handle_
->GetDevice());
125 const UsbConfigDescriptor
* config
=
126 device_handle_
->GetDevice()->GetConfiguration();
127 info
->configurations
= mojo::Array
<ConfigurationInfoPtr
>::New(0);
129 info
->configurations
.push_back(ConfigurationInfo::From(*config
));
130 callback
.Run(info
.Pass());
133 void DeviceImpl::SetConfiguration(uint8_t value
,
134 const SetConfigurationCallback
& callback
) {
135 if (!device_handle_
) {
140 device_handle_
->SetConfiguration(value
, WrapMojoCallback(callback
));
143 void DeviceImpl::ClaimInterface(uint8_t interface_number
,
144 const ClaimInterfaceCallback
& callback
) {
145 if (!device_handle_
) {
150 device_handle_
->ClaimInterface(interface_number
, WrapMojoCallback(callback
));
153 void DeviceImpl::ReleaseInterface(uint8_t interface_number
,
154 const ReleaseInterfaceCallback
& callback
) {
155 if (!device_handle_
) {
160 callback
.Run(device_handle_
->ReleaseInterface(interface_number
));
163 void DeviceImpl::SetInterfaceAlternateSetting(
164 uint8_t interface_number
,
165 uint8_t alternate_setting
,
166 const SetInterfaceAlternateSettingCallback
& callback
) {
167 if (!device_handle_
) {
172 device_handle_
->SetInterfaceAlternateSetting(
173 interface_number
, alternate_setting
, WrapMojoCallback(callback
));
176 void DeviceImpl::Reset(const ResetCallback
& callback
) {
177 if (!device_handle_
) {
182 device_handle_
->ResetDevice(WrapMojoCallback(callback
));
185 void DeviceImpl::ControlTransferIn(ControlTransferParamsPtr params
,
188 const ControlTransferInCallback
& callback
) {
189 if (!device_handle_
) {
190 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<uint8_t>());
194 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(length
);
195 device_handle_
->ControlTransfer(
196 USB_DIRECTION_INBOUND
,
197 mojo::ConvertTo
<UsbDeviceHandle::TransferRequestType
>(params
->type
),
198 mojo::ConvertTo
<UsbDeviceHandle::TransferRecipient
>(params
->recipient
),
199 params
->request
, params
->value
, params
->index
, buffer
, length
, timeout
,
200 base::Bind(&DeviceImpl::OnTransferIn
, weak_factory_
.GetWeakPtr(),
204 void DeviceImpl::ControlTransferOut(
205 ControlTransferParamsPtr params
,
206 mojo::Array
<uint8_t> data
,
208 const ControlTransferOutCallback
& callback
) {
209 if (!device_handle_
) {
210 callback
.Run(TRANSFER_STATUS_ERROR
);
214 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(data
.size());
215 const std::vector
<uint8_t>& storage
= data
.storage();
216 std::copy(storage
.begin(), storage
.end(), buffer
->data());
217 device_handle_
->ControlTransfer(
218 USB_DIRECTION_OUTBOUND
,
219 mojo::ConvertTo
<UsbDeviceHandle::TransferRequestType
>(params
->type
),
220 mojo::ConvertTo
<UsbDeviceHandle::TransferRecipient
>(params
->recipient
),
221 params
->request
, params
->value
, params
->index
, buffer
, data
.size(),
222 timeout
, base::Bind(&DeviceImpl::OnTransferOut
,
223 weak_factory_
.GetWeakPtr(), callback
));
226 void DeviceImpl::BulkTransferIn(uint8_t endpoint_number
,
229 const BulkTransferInCallback
& callback
) {
230 if (!device_handle_
) {
231 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<uint8_t>());
235 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(length
);
236 device_handle_
->BulkTransfer(
237 USB_DIRECTION_INBOUND
, endpoint_number
, buffer
, length
, timeout
,
238 base::Bind(&DeviceImpl::OnTransferIn
, weak_factory_
.GetWeakPtr(),
242 void DeviceImpl::BulkTransferOut(uint8_t endpoint_number
,
243 mojo::Array
<uint8_t> data
,
245 const BulkTransferOutCallback
& callback
) {
246 if (!device_handle_
) {
247 callback
.Run(TRANSFER_STATUS_ERROR
);
251 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(data
.size());
252 const std::vector
<uint8_t>& storage
= data
.storage();
253 std::copy(storage
.begin(), storage
.end(), buffer
->data());
254 device_handle_
->BulkTransfer(
255 USB_DIRECTION_OUTBOUND
, endpoint_number
, buffer
, data
.size(), timeout
,
256 base::Bind(&DeviceImpl::OnTransferOut
, weak_factory_
.GetWeakPtr(),
260 void DeviceImpl::InterruptTransferIn(
261 uint8_t endpoint_number
,
264 const InterruptTransferInCallback
& callback
) {
265 if (!device_handle_
) {
266 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<uint8_t>());
270 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(length
);
271 device_handle_
->InterruptTransfer(
272 USB_DIRECTION_INBOUND
, endpoint_number
, buffer
, length
, timeout
,
273 base::Bind(&DeviceImpl::OnTransferIn
, weak_factory_
.GetWeakPtr(),
277 void DeviceImpl::InterruptTransferOut(
278 uint8_t endpoint_number
,
279 mojo::Array
<uint8_t> data
,
281 const InterruptTransferOutCallback
& callback
) {
282 if (!device_handle_
) {
283 callback
.Run(TRANSFER_STATUS_ERROR
);
287 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(data
.size());
288 const std::vector
<uint8_t>& storage
= data
.storage();
289 std::copy(storage
.begin(), storage
.end(), buffer
->data());
290 device_handle_
->InterruptTransfer(
291 USB_DIRECTION_OUTBOUND
, endpoint_number
, buffer
, data
.size(), timeout
,
292 base::Bind(&DeviceImpl::OnTransferOut
, weak_factory_
.GetWeakPtr(),
296 void DeviceImpl::IsochronousTransferIn(
297 uint8_t endpoint_number
,
298 uint32_t num_packets
,
299 uint32_t packet_length
,
301 const IsochronousTransferInCallback
& callback
) {
302 if (!device_handle_
) {
303 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<mojo::Array
<uint8_t>>());
307 size_t transfer_size
= static_cast<size_t>(num_packets
) * packet_length
;
308 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(transfer_size
);
309 device_handle_
->IsochronousTransfer(
310 USB_DIRECTION_INBOUND
, endpoint_number
, buffer
, transfer_size
,
311 num_packets
, packet_length
, timeout
,
312 base::Bind(&DeviceImpl::OnIsochronousTransferIn
,
313 weak_factory_
.GetWeakPtr(), callback
, packet_length
));
316 void DeviceImpl::IsochronousTransferOut(
317 uint8_t endpoint_number
,
318 mojo::Array
<mojo::Array
<uint8_t>> packets
,
320 const IsochronousTransferOutCallback
& callback
) {
321 if (!device_handle_
) {
322 callback
.Run(TRANSFER_STATUS_ERROR
);
326 uint32_t packet_size
= 0;
327 for (size_t i
= 0; i
< packets
.size(); ++i
) {
329 std::max(packet_size
, static_cast<uint32_t>(packets
[i
].size()));
331 size_t transfer_size
= packet_size
* packets
.size();
332 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(transfer_size
);
333 memset(buffer
->data(), 0, transfer_size
);
334 for (size_t i
= 0; i
< packets
.size(); ++i
) {
336 reinterpret_cast<uint8_t*>(&buffer
->data()[i
* packet_size
]);
337 DCHECK_LE(packets
[i
].size(), static_cast<size_t>(packet_size
));
338 memcpy(packet
, packets
[i
].storage().data(), packets
[i
].size());
340 device_handle_
->IsochronousTransfer(
341 USB_DIRECTION_OUTBOUND
, endpoint_number
, buffer
, transfer_size
,
342 static_cast<uint32_t>(packets
.size()), packet_size
, timeout
,
343 base::Bind(&DeviceImpl::OnIsochronousTransferOut
,
344 weak_factory_
.GetWeakPtr(), callback
));
348 } // namespace device