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
<UsbDevice
> device
,
43 mojo::InterfaceRequest
<Device
> request
)
44 : binding_(this, request
.Pass()), device_(device
), weak_factory_(this) {}
46 DeviceImpl::~DeviceImpl() {
50 void DeviceImpl::CloseHandle() {
52 device_handle_
->Close();
53 device_handle_
= nullptr;
56 void DeviceImpl::OnOpen(const OpenCallback
& callback
,
57 scoped_refptr
<UsbDeviceHandle
> handle
) {
58 device_handle_
= handle
;
59 callback
.Run(handle
? OPEN_DEVICE_ERROR_OK
: OPEN_DEVICE_ERROR_ACCESS_DENIED
);
62 void DeviceImpl::OnTransferIn(const MojoTransferInCallback
& callback
,
63 UsbTransferStatus status
,
64 scoped_refptr
<net::IOBuffer
> buffer
,
66 mojo::Array
<uint8_t> data
;
68 // TODO(rockot/reillyg): We should change UsbDeviceHandle to use a
69 // std::vector<uint8_t> instead of net::IOBuffer. Then we could move
71 std::vector
<uint8_t> bytes(buffer_size
);
72 std::copy(buffer
->data(), buffer
->data() + buffer_size
, bytes
.begin());
75 callback
.Run(mojo::ConvertTo
<TransferStatus
>(status
), data
.Pass());
78 void DeviceImpl::OnTransferOut(const MojoTransferOutCallback
& callback
,
79 UsbTransferStatus status
,
80 scoped_refptr
<net::IOBuffer
> buffer
,
82 callback
.Run(mojo::ConvertTo
<TransferStatus
>(status
));
85 void DeviceImpl::OnIsochronousTransferIn(
86 const IsochronousTransferInCallback
& callback
,
88 UsbTransferStatus status
,
89 scoped_refptr
<net::IOBuffer
> buffer
,
91 size_t num_packets
= buffer_size
/ packet_size
;
92 mojo::Array
<mojo::Array
<uint8_t>> packets(num_packets
);
94 for (size_t i
= 0; i
< num_packets
; ++i
) {
95 size_t packet_index
= i
* packet_size
;
96 std::vector
<uint8_t> bytes(packet_size
);
97 std::copy(buffer
->data() + packet_index
,
98 buffer
->data() + packet_index
+ packet_size
, bytes
.begin());
99 packets
[i
].Swap(&bytes
);
102 callback
.Run(mojo::ConvertTo
<TransferStatus
>(status
), packets
.Pass());
105 void DeviceImpl::OnIsochronousTransferOut(
106 const MojoTransferOutCallback
& callback
,
107 UsbTransferStatus status
,
108 scoped_refptr
<net::IOBuffer
> buffer
,
109 size_t buffer_size
) {
110 callback
.Run(mojo::ConvertTo
<TransferStatus
>(status
));
113 void DeviceImpl::GetDeviceInfo(const GetDeviceInfoCallback
& callback
) {
114 callback
.Run(DeviceInfo::From(*device_
));
117 void DeviceImpl::GetConfiguration(const GetConfigurationCallback
& callback
) {
118 const UsbConfigDescriptor
* config
= device_
->GetActiveConfiguration();
119 callback
.Run(config
? ConfigurationInfo::From(*config
) : nullptr);
122 void DeviceImpl::Open(const OpenCallback
& callback
) {
124 base::Bind(&DeviceImpl::OnOpen
, weak_factory_
.GetWeakPtr(), callback
));
127 void DeviceImpl::Close(const CloseCallback
& callback
) {
132 void DeviceImpl::SetConfiguration(uint8_t value
,
133 const SetConfigurationCallback
& callback
) {
134 if (!device_handle_
) {
139 device_handle_
->SetConfiguration(value
, WrapMojoCallback(callback
));
142 void DeviceImpl::ClaimInterface(uint8_t interface_number
,
143 const ClaimInterfaceCallback
& callback
) {
144 if (!device_handle_
) {
149 device_handle_
->ClaimInterface(interface_number
, WrapMojoCallback(callback
));
152 void DeviceImpl::ReleaseInterface(uint8_t interface_number
,
153 const ReleaseInterfaceCallback
& callback
) {
154 if (!device_handle_
) {
159 callback
.Run(device_handle_
->ReleaseInterface(interface_number
));
162 void DeviceImpl::SetInterfaceAlternateSetting(
163 uint8_t interface_number
,
164 uint8_t alternate_setting
,
165 const SetInterfaceAlternateSettingCallback
& callback
) {
166 if (!device_handle_
) {
171 device_handle_
->SetInterfaceAlternateSetting(
172 interface_number
, alternate_setting
, WrapMojoCallback(callback
));
175 void DeviceImpl::Reset(const ResetCallback
& callback
) {
176 if (!device_handle_
) {
181 device_handle_
->ResetDevice(WrapMojoCallback(callback
));
184 void DeviceImpl::ClearHalt(uint8_t endpoint
,
185 const ClearHaltCallback
& callback
) {
186 if (!device_handle_
) {
191 device_handle_
->ClearHalt(endpoint
, WrapMojoCallback(callback
));
194 void DeviceImpl::ControlTransferIn(ControlTransferParamsPtr params
,
197 const ControlTransferInCallback
& callback
) {
198 if (!device_handle_
) {
199 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<uint8_t>());
203 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(length
);
204 device_handle_
->ControlTransfer(
205 USB_DIRECTION_INBOUND
,
206 mojo::ConvertTo
<UsbDeviceHandle::TransferRequestType
>(params
->type
),
207 mojo::ConvertTo
<UsbDeviceHandle::TransferRecipient
>(params
->recipient
),
208 params
->request
, params
->value
, params
->index
, buffer
, length
, timeout
,
209 base::Bind(&DeviceImpl::OnTransferIn
, weak_factory_
.GetWeakPtr(),
213 void DeviceImpl::ControlTransferOut(
214 ControlTransferParamsPtr params
,
215 mojo::Array
<uint8_t> data
,
217 const ControlTransferOutCallback
& callback
) {
218 if (!device_handle_
) {
219 callback
.Run(TRANSFER_STATUS_ERROR
);
223 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(data
.size());
224 const std::vector
<uint8_t>& storage
= data
.storage();
225 std::copy(storage
.begin(), storage
.end(), buffer
->data());
226 device_handle_
->ControlTransfer(
227 USB_DIRECTION_OUTBOUND
,
228 mojo::ConvertTo
<UsbDeviceHandle::TransferRequestType
>(params
->type
),
229 mojo::ConvertTo
<UsbDeviceHandle::TransferRecipient
>(params
->recipient
),
230 params
->request
, params
->value
, params
->index
, buffer
, data
.size(),
231 timeout
, base::Bind(&DeviceImpl::OnTransferOut
,
232 weak_factory_
.GetWeakPtr(), callback
));
235 void DeviceImpl::GenericTransferIn(uint8_t endpoint_number
,
238 const GenericTransferInCallback
& callback
) {
239 if (!device_handle_
) {
240 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<uint8_t>());
244 uint8_t endpoint_address
= endpoint_number
| 0x80;
245 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(length
);
246 device_handle_
->GenericTransfer(
247 USB_DIRECTION_INBOUND
, endpoint_address
, buffer
, length
, timeout
,
248 base::Bind(&DeviceImpl::OnTransferIn
, weak_factory_
.GetWeakPtr(),
252 void DeviceImpl::GenericTransferOut(
253 uint8_t endpoint_number
,
254 mojo::Array
<uint8_t> data
,
256 const GenericTransferOutCallback
& callback
) {
257 if (!device_handle_
) {
258 callback
.Run(TRANSFER_STATUS_ERROR
);
262 uint8_t endpoint_address
= endpoint_number
;
263 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(data
.size());
264 const std::vector
<uint8_t>& storage
= data
.storage();
265 std::copy(storage
.begin(), storage
.end(), buffer
->data());
266 device_handle_
->GenericTransfer(
267 USB_DIRECTION_OUTBOUND
, endpoint_address
, buffer
, data
.size(), timeout
,
268 base::Bind(&DeviceImpl::OnTransferOut
, weak_factory_
.GetWeakPtr(),
272 void DeviceImpl::IsochronousTransferIn(
273 uint8_t endpoint_number
,
274 uint32_t num_packets
,
275 uint32_t packet_length
,
277 const IsochronousTransferInCallback
& callback
) {
278 if (!device_handle_
) {
279 callback
.Run(TRANSFER_STATUS_ERROR
, mojo::Array
<mojo::Array
<uint8_t>>());
283 uint8_t endpoint_address
= endpoint_number
| 0x80;
284 size_t transfer_size
= static_cast<size_t>(num_packets
) * packet_length
;
285 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(transfer_size
);
286 device_handle_
->IsochronousTransfer(
287 USB_DIRECTION_INBOUND
, endpoint_address
, buffer
, transfer_size
,
288 num_packets
, packet_length
, timeout
,
289 base::Bind(&DeviceImpl::OnIsochronousTransferIn
,
290 weak_factory_
.GetWeakPtr(), callback
, packet_length
));
293 void DeviceImpl::IsochronousTransferOut(
294 uint8_t endpoint_number
,
295 mojo::Array
<mojo::Array
<uint8_t>> packets
,
297 const IsochronousTransferOutCallback
& callback
) {
298 if (!device_handle_
) {
299 callback
.Run(TRANSFER_STATUS_ERROR
);
303 uint8_t endpoint_address
= endpoint_number
;
304 uint32_t packet_size
= 0;
305 for (size_t i
= 0; i
< packets
.size(); ++i
) {
307 std::max(packet_size
, static_cast<uint32_t>(packets
[i
].size()));
309 size_t transfer_size
= packet_size
* packets
.size();
310 scoped_refptr
<net::IOBuffer
> buffer
= CreateTransferBuffer(transfer_size
);
311 memset(buffer
->data(), 0, transfer_size
);
312 for (size_t i
= 0; i
< packets
.size(); ++i
) {
314 reinterpret_cast<uint8_t*>(&buffer
->data()[i
* packet_size
]);
315 DCHECK_LE(packets
[i
].size(), static_cast<size_t>(packet_size
));
316 memcpy(packet
, packets
[i
].storage().data(), packets
[i
].size());
318 device_handle_
->IsochronousTransfer(
319 USB_DIRECTION_OUTBOUND
, endpoint_address
, buffer
, transfer_size
,
320 static_cast<uint32_t>(packets
.size()), packet_size
, timeout
,
321 base::Bind(&DeviceImpl::OnIsochronousTransferOut
,
322 weak_factory_
.GetWeakPtr(), callback
));
326 } // namespace device