| 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 |