Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/usb/usb_device_handle.h" | 5 #include "chrome/browser/usb/usb_device_handle.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
| 12 #include "base/synchronization/lock.h" | 12 #include "base/synchronization/lock.h" |
| 13 #include "chrome/browser/usb/usb_context.h" | |
| 13 #include "chrome/browser/usb/usb_device.h" | 14 #include "chrome/browser/usb/usb_device.h" |
| 14 #include "chrome/browser/usb/usb_interface.h" | 15 #include "chrome/browser/usb/usb_interface.h" |
| 15 #include "chrome/browser/usb/usb_service.h" | 16 #include "chrome/browser/usb/usb_service.h" |
| 16 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
| 17 #include "third_party/libusb/src/libusb/libusb.h" | 18 #include "third_party/libusb/src/libusb/libusb.h" |
| 18 | 19 |
| 19 using content::BrowserThread; | 20 using content::BrowserThread; |
| 21 void HandleTransferCompletion(PlatformUsbTransferHandle transfer); | |
| 20 | 22 |
| 21 namespace { | 23 namespace { |
| 22 | 24 |
| 23 static uint8 ConvertTransferDirection( | 25 static uint8 ConvertTransferDirection( |
| 24 const UsbEndpointDirection direction) { | 26 const UsbEndpointDirection direction) { |
| 25 switch (direction) { | 27 switch (direction) { |
| 26 case USB_DIRECTION_INBOUND: | 28 case USB_DIRECTION_INBOUND: |
| 27 return LIBUSB_ENDPOINT_IN; | 29 return LIBUSB_ENDPOINT_IN; |
| 28 case USB_DIRECTION_OUTBOUND: | 30 case USB_DIRECTION_OUTBOUND: |
| 29 return LIBUSB_ENDPOINT_OUT; | 31 return LIBUSB_ENDPOINT_OUT; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 case LIBUSB_TRANSFER_OVERFLOW: | 89 case LIBUSB_TRANSFER_OVERFLOW: |
| 88 return USB_TRANSFER_OVERFLOW; | 90 return USB_TRANSFER_OVERFLOW; |
| 89 case LIBUSB_TRANSFER_CANCELLED: | 91 case LIBUSB_TRANSFER_CANCELLED: |
| 90 return USB_TRANSFER_CANCELLED; | 92 return USB_TRANSFER_CANCELLED; |
| 91 default: | 93 default: |
| 92 NOTREACHED(); | 94 NOTREACHED(); |
| 93 return USB_TRANSFER_ERROR; | 95 return USB_TRANSFER_ERROR; |
| 94 } | 96 } |
| 95 } | 97 } |
| 96 | 98 |
| 97 static void LIBUSB_CALL HandleTransferCompletion( | 99 static void LIBUSB_CALL PlatformTransferCompletionCallback( |
| 98 struct libusb_transfer* transfer) { | 100 PlatformUsbTransferHandle transfer) { |
| 99 UsbDeviceHandle* const device = | 101 BrowserThread::PostTask(BrowserThread::FILE, |
| 100 reinterpret_cast<UsbDeviceHandle*>(transfer->user_data); | 102 FROM_HERE, |
| 101 device->TransferComplete(transfer); | 103 base::Bind(HandleTransferCompletion, transfer)); |
| 102 } | 104 } |
| 103 | 105 |
| 104 } // namespace | 106 } // namespace |
| 105 | 107 |
| 108 void HandleTransferCompletion(PlatformUsbTransferHandle transfer) { | |
| 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 110 UsbDeviceHandle* const device_handle = | |
| 111 reinterpret_cast<UsbDeviceHandle*>(transfer->user_data); | |
| 112 CHECK(device_handle) << "Device handle is closed before transfer finishes."; | |
| 113 device_handle->TransferComplete(transfer); | |
| 114 libusb_free_transfer(transfer); | |
| 115 } | |
| 116 | |
| 117 UsbDeviceHandle::InterfaceClaimer::InterfaceClaimer( | |
| 118 const PlatformUsbDeviceHandle handle, const int interface_number) | |
| 119 : handle_(handle), | |
| 120 interface_number_(interface_number), | |
| 121 alternate_setting_(0) { | |
| 122 } | |
| 123 | |
| 124 UsbDeviceHandle::InterfaceClaimer::~InterfaceClaimer() { | |
| 125 libusb_release_interface(handle_, interface_number_); | |
| 126 } | |
| 127 | |
| 106 UsbDeviceHandle::Transfer::Transfer() | 128 UsbDeviceHandle::Transfer::Transfer() |
| 107 : transfer_type(USB_TRANSFER_CONTROL), | 129 : transfer_type(USB_TRANSFER_CONTROL), |
| 108 length(0) { | 130 length(0) { |
| 109 } | 131 } |
| 110 | 132 |
| 111 UsbDeviceHandle::Transfer::~Transfer() {} | 133 UsbDeviceHandle::Transfer::~Transfer() {} |
| 112 | 134 |
| 113 UsbDeviceHandle::UsbDeviceHandle( | 135 UsbDeviceHandle::UsbDeviceHandle( |
| 136 scoped_refptr<UsbContext> context, | |
| 114 UsbDevice* device, | 137 UsbDevice* device, |
| 115 PlatformUsbDeviceHandle handle) | 138 PlatformUsbDeviceHandle handle) |
| 116 : device_(device), handle_(handle) { | 139 : device_(device), handle_(handle), context_(context) { |
| 117 DCHECK(thread_checker_.CalledOnValidThread()); | 140 DCHECK(thread_checker_.CalledOnValidThread()); |
| 118 DCHECK(handle) << "Cannot create device with NULL handle."; | 141 DCHECK(handle) << "Cannot create device with NULL handle."; |
| 142 interfaces_ = new UsbConfigDescriptor(); | |
| 143 device->ListInterfaces(interfaces_.get()); | |
| 119 } | 144 } |
| 120 | 145 |
| 121 UsbDeviceHandle::UsbDeviceHandle() : device_(NULL), handle_(NULL) { | 146 UsbDeviceHandle::UsbDeviceHandle() : device_(NULL), handle_(NULL) { |
| 122 } | 147 } |
| 123 | 148 |
| 124 UsbDeviceHandle::~UsbDeviceHandle() { | 149 UsbDeviceHandle::~UsbDeviceHandle() { |
| 125 DCHECK(thread_checker_.CalledOnValidThread()); | 150 DCHECK(thread_checker_.CalledOnValidThread()); |
| 126 Close(); | 151 |
| 152 libusb_close(handle_); | |
| 153 handle_ = NULL; | |
| 127 } | 154 } |
| 128 | 155 |
| 129 scoped_refptr<UsbDevice> UsbDeviceHandle::device() const { | 156 scoped_refptr<UsbDevice> UsbDeviceHandle::device() const { |
| 130 return device_; | 157 return device_; |
| 131 } | 158 } |
| 132 | 159 |
| 133 void UsbDeviceHandle::Close() { | 160 void UsbDeviceHandle::Close() { |
| 134 DCHECK(thread_checker_.CalledOnValidThread()); | 161 DCHECK(thread_checker_.CalledOnValidThread()); |
| 135 if (handle_) | 162 if (device_) |
| 136 device_->Close(this); | 163 device_->Close(this); |
| 137 } | 164 } |
| 138 | 165 |
| 139 void UsbDeviceHandle::TransferComplete(PlatformUsbTransferHandle handle) { | 166 void UsbDeviceHandle::TransferComplete(PlatformUsbTransferHandle handle) { |
| 140 base::AutoLock lock(lock_); | 167 DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed"; |
| 141 | 168 |
| 142 // TODO(gdk): Handle device disconnect. | 169 Transfer transfer = transfers_[handle]; |
| 143 DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed"; | 170 transfers_.erase(handle); |
| 144 Transfer* const transfer = &transfers_[handle]; | |
| 145 | 171 |
| 146 DCHECK_GE(handle->actual_length, 0) << "Negative actual length received"; | 172 DCHECK_GE(handle->actual_length, 0) << "Negative actual length received"; |
| 147 size_t actual_length = | 173 size_t actual_length = |
| 148 static_cast<size_t>(std::max(handle->actual_length, 0)); | 174 static_cast<size_t>(std::max(handle->actual_length, 0)); |
| 149 | 175 |
| 150 DCHECK(transfer->length >= actual_length) << | 176 DCHECK(transfer.length >= actual_length) << |
| 151 "data too big for our buffer (libusb failure?)"; | 177 "data too big for our buffer (libusb failure?)"; |
| 152 | 178 |
| 153 scoped_refptr<net::IOBuffer> buffer = transfer->buffer; | 179 scoped_refptr<net::IOBuffer> buffer = transfer.buffer; |
| 154 switch (transfer->transfer_type) { | 180 switch (transfer.transfer_type) { |
| 155 case USB_TRANSFER_CONTROL: | 181 case USB_TRANSFER_CONTROL: |
| 156 // If the transfer is a control transfer we do not expose the control | 182 // If the transfer is a control transfer we do not expose the control |
| 157 // setup header to the caller. This logic strips off the header if | 183 // setup header to the caller. This logic strips off the header if |
| 158 // present before invoking the callback provided with the transfer. | 184 // present before invoking the callback provided with the transfer. |
| 159 if (actual_length > 0) { | 185 if (actual_length > 0) { |
| 160 CHECK(transfer->length >= LIBUSB_CONTROL_SETUP_SIZE) << | 186 CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) << |
| 161 "buffer was not correctly set: too small for the control header"; | 187 "buffer was not correctly set: too small for the control header"; |
| 162 | 188 |
| 163 if (transfer->length >= actual_length && | 189 if (transfer.length >= actual_length && |
| 164 actual_length >= LIBUSB_CONTROL_SETUP_SIZE) { | 190 actual_length >= LIBUSB_CONTROL_SETUP_SIZE) { |
| 165 // If the payload is zero bytes long, pad out the allocated buffer | 191 // If the payload is zero bytes long, pad out the allocated buffer |
| 166 // size to one byte so that an IOBuffer of that size can be allocated. | 192 // size to one byte so that an IOBuffer of that size can be allocated. |
| 167 scoped_refptr<net::IOBuffer> resized_buffer = new net::IOBuffer( | 193 scoped_refptr<net::IOBuffer> resized_buffer = new net::IOBuffer( |
| 168 std::max(actual_length, static_cast<size_t>(1))); | 194 std::max(actual_length, static_cast<size_t>(1))); |
| 169 memcpy(resized_buffer->data(), | 195 memcpy(resized_buffer->data(), |
| 170 buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, | 196 buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, |
| 171 actual_length); | 197 actual_length); |
| 172 buffer = resized_buffer; | 198 buffer = resized_buffer; |
| 173 } | 199 } |
| 174 } | 200 } |
| 175 break; | 201 break; |
| 176 | 202 |
| 177 case USB_TRANSFER_ISOCHRONOUS: | 203 case USB_TRANSFER_ISOCHRONOUS: |
| 178 // Isochronous replies might carry data in the different isoc packets even | 204 // Isochronous replies might carry data in the different isoc packets even |
| 179 // if the transfer actual_data value is zero. Furthermore, not all of the | 205 // if the transfer actual_data value is zero. Furthermore, not all of the |
| 180 // received packets might contain data, so we need to calculate how many | 206 // received packets might contain data, so we need to calculate how many |
| 181 // data bytes we are effectively providing and pack the results. | 207 // data bytes we are effectively providing and pack the results. |
| 182 if (actual_length == 0) { | 208 if (actual_length == 0) { |
| 183 size_t packet_buffer_start = 0; | 209 size_t packet_buffer_start = 0; |
| 184 for (int i = 0; i < handle->num_iso_packets; ++i) { | 210 for (int i = 0; i < handle->num_iso_packets; ++i) { |
| 185 PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i]; | 211 PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i]; |
| 186 if (packet->actual_length > 0) { | 212 if (packet->actual_length > 0) { |
| 187 // We don't need to copy as long as all packets until now provide | 213 // We don't need to copy as long as all packets until now provide |
| 188 // all the data the packet can hold. | 214 // all the data the packet can hold. |
| 189 if (actual_length < packet_buffer_start) { | 215 if (actual_length < packet_buffer_start) { |
| 190 CHECK(packet_buffer_start + packet->actual_length <= | 216 CHECK(packet_buffer_start + packet->actual_length <= |
| 191 transfer->length); | 217 transfer.length); |
| 192 memmove(buffer->data() + actual_length, | 218 memmove(buffer->data() + actual_length, |
| 193 buffer->data() + packet_buffer_start, | 219 buffer->data() + packet_buffer_start, |
| 194 packet->actual_length); | 220 packet->actual_length); |
| 195 } | 221 } |
| 196 actual_length += packet->actual_length; | 222 actual_length += packet->actual_length; |
| 197 } | 223 } |
| 198 | 224 |
| 199 packet_buffer_start += packet->length; | 225 packet_buffer_start += packet->length; |
| 200 } | 226 } |
| 201 } | 227 } |
| 202 break; | 228 break; |
| 203 | 229 |
| 204 case USB_TRANSFER_BULK: | 230 case USB_TRANSFER_BULK: |
| 205 case USB_TRANSFER_INTERRUPT: | 231 case USB_TRANSFER_INTERRUPT: |
| 206 break; | 232 break; |
| 207 | 233 |
| 208 default: | 234 default: |
| 209 NOTREACHED() << "Invalid usb transfer type"; | 235 NOTREACHED() << "Invalid usb transfer type"; |
| 210 break; | 236 break; |
| 211 } | 237 } |
| 212 | 238 |
| 213 transfer->callback.Run(ConvertTransferStatus(handle->status), buffer, | 239 transfer.callback.Run(ConvertTransferStatus(handle->status), buffer, |
|
pfeldman
2013/08/09 08:58:59
You should respond on the thread transfer was requ
Bei Zhang
2013/08/09 16:43:55
Done.
| |
| 214 actual_length); | 240 actual_length); |
| 215 | 241 |
| 216 transfers_.erase(handle); | 242 // Must release interface first before actually delete this. |
| 217 libusb_free_transfer(handle); | 243 transfer.claimed_interface = NULL; |
| 244 | |
| 245 Release(); | |
| 218 } | 246 } |
| 219 | 247 |
| 220 bool UsbDeviceHandle::ClaimInterface(const int interface_number) { | 248 bool UsbDeviceHandle::ClaimInterface(const int interface_number) { |
| 221 DCHECK(thread_checker_.CalledOnValidThread()); | 249 DCHECK(thread_checker_.CalledOnValidThread()); |
| 222 if (!handle_) return false; | 250 if (!device_) return false; |
| 251 if (ContainsKey(claimed_interfaces_, interface_number)) return true; | |
| 223 | 252 |
| 224 const int claim_result = libusb_claim_interface(handle_, interface_number); | 253 const int rv = libusb_claim_interface(handle_, interface_number); |
|
pfeldman
2013/08/09 08:58:59
I think libusb_claim_interface and free_interface
Bei Zhang
2013/08/09 16:43:55
Done.
| |
| 225 return claim_result == 0; | 254 if (rv ==0) { |
| 255 claimed_interfaces_[interface_number]= | |
| 256 new InterfaceClaimer(handle_, interface_number); | |
| 257 RefreshEndpointMap(); | |
| 258 return true; | |
| 259 } | |
| 260 return false; | |
| 226 } | 261 } |
| 227 | 262 |
| 228 bool UsbDeviceHandle::ReleaseInterface(const int interface_number) { | 263 bool UsbDeviceHandle::ReleaseInterface(const int interface_number) { |
| 229 DCHECK(thread_checker_.CalledOnValidThread()); | 264 DCHECK(thread_checker_.CalledOnValidThread()); |
| 230 if (!handle_) return false; | 265 if (!device_) return false; |
| 266 if (!ContainsKey(claimed_interfaces_, interface_number)) return false; | |
| 231 | 267 |
| 232 const int release_result = libusb_release_interface(handle_, | 268 // Cancel all the transfers on that interface. |
| 233 interface_number); | 269 InterfaceClaimer* interface_claimer = |
| 234 return release_result == 0; | 270 claimed_interfaces_[interface_number].get(); |
| 271 for (TransferMap::iterator it = transfers_.begin(); | |
| 272 it != transfers_.end(); ++it) { | |
| 273 if (it->second.claimed_interface.get() == interface_claimer) | |
| 274 libusb_cancel_transfer(it->first); | |
| 275 } | |
| 276 claimed_interfaces_.erase(interface_number); | |
| 277 | |
| 278 RefreshEndpointMap(); | |
| 279 return true; | |
| 235 } | 280 } |
| 236 | 281 |
| 237 bool UsbDeviceHandle::SetInterfaceAlternateSetting( | 282 bool UsbDeviceHandle::SetInterfaceAlternateSetting( |
| 238 const int interface_number, | 283 const int interface_number, |
| 239 const int alternate_setting) { | 284 const int alternate_setting) { |
| 240 DCHECK(thread_checker_.CalledOnValidThread()); | 285 DCHECK(thread_checker_.CalledOnValidThread()); |
| 241 if (!handle_) return false; | 286 if (!device_) return false; |
| 242 | 287 if (!ContainsKey(claimed_interfaces_, interface_number)) return false; |
| 243 const int setting_result = libusb_set_interface_alt_setting(handle_, | 288 const int rv = libusb_set_interface_alt_setting(handle_, |
| 244 interface_number, alternate_setting); | 289 interface_number, alternate_setting); |
| 245 | 290 if (rv == 0) { |
| 246 return setting_result == 0; | 291 claimed_interfaces_[interface_number]-> |
| 292 set_alternate_setting(alternate_setting); | |
| 293 RefreshEndpointMap(); | |
| 294 return true; | |
| 295 } | |
| 296 return false; | |
| 247 } | 297 } |
| 248 | 298 |
| 249 bool UsbDeviceHandle::ResetDevice() { | 299 bool UsbDeviceHandle::ResetDevice() { |
| 250 DCHECK(thread_checker_.CalledOnValidThread()); | 300 DCHECK(thread_checker_.CalledOnValidThread()); |
| 251 if (!handle_) return false; | 301 if (!device_) return false; |
| 252 | 302 |
| 253 return libusb_reset_device(handle_) == 0; | 303 return libusb_reset_device(handle_) == 0; |
| 254 } | 304 } |
| 255 | 305 |
| 256 bool UsbDeviceHandle::GetSerial(base::string16* serial) { | 306 bool UsbDeviceHandle::GetSerial(base::string16* serial) { |
| 257 DCHECK(thread_checker_.CalledOnValidThread()); | 307 DCHECK(thread_checker_.CalledOnValidThread()); |
| 258 PlatformUsbDevice device = libusb_get_device(handle_); | 308 PlatformUsbDevice device = libusb_get_device(handle_); |
| 259 libusb_device_descriptor desc; | 309 libusb_device_descriptor desc; |
| 260 | 310 |
| 261 if (libusb_get_device_descriptor(device, &desc) != LIBUSB_SUCCESS) | 311 if (libusb_get_device_descriptor(device, &desc) != LIBUSB_SUCCESS) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 return true; | 343 return true; |
| 294 } | 344 } |
| 295 return false; | 345 return false; |
| 296 } | 346 } |
| 297 | 347 |
| 298 void UsbDeviceHandle::ControlTransfer(const UsbEndpointDirection direction, | 348 void UsbDeviceHandle::ControlTransfer(const UsbEndpointDirection direction, |
| 299 const TransferRequestType request_type, const TransferRecipient recipient, | 349 const TransferRequestType request_type, const TransferRecipient recipient, |
| 300 const uint8 request, const uint16 value, const uint16 index, | 350 const uint8 request, const uint16 value, const uint16 index, |
| 301 net::IOBuffer* buffer, const size_t length, const unsigned int timeout, | 351 net::IOBuffer* buffer, const size_t length, const unsigned int timeout, |
| 302 const UsbTransferCallback& callback) { | 352 const UsbTransferCallback& callback) { |
| 303 if (!handle_) { | 353 if (!device_) { |
| 304 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | 354 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); |
| 305 return; | 355 return; |
| 306 } | 356 } |
| 307 | 357 |
| 308 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length; | 358 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length; |
| 309 scoped_refptr<net::IOBuffer> resized_buffer(new net::IOBufferWithSize( | 359 scoped_refptr<net::IOBuffer> resized_buffer(new net::IOBufferWithSize( |
| 310 resized_length)); | 360 resized_length)); |
| 311 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(), | 361 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(), |
| 312 length); | 362 length); |
| 313 | 363 |
| 314 struct libusb_transfer* const transfer = libusb_alloc_transfer(0); | 364 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); |
| 315 const uint8 converted_type = CreateRequestType(direction, request_type, | 365 const uint8 converted_type = CreateRequestType(direction, request_type, |
| 316 recipient); | 366 recipient); |
| 317 libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()), | 367 libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()), |
| 318 converted_type, request, value, index, length); | 368 converted_type, request, value, index, length); |
| 319 libusb_fill_control_transfer(transfer, handle_, reinterpret_cast<uint8*>( | 369 libusb_fill_control_transfer( |
| 320 resized_buffer->data()), HandleTransferCompletion, this, timeout); | 370 transfer, |
| 321 SubmitTransfer(transfer, | 371 handle_, |
| 372 reinterpret_cast<uint8*>(resized_buffer->data()), | |
| 373 PlatformTransferCompletionCallback, | |
| 374 this, | |
| 375 timeout); | |
| 376 | |
| 377 BrowserThread::PostTask( | |
| 378 BrowserThread::FILE, | |
| 379 FROM_HERE, | |
| 380 base::Bind(&UsbDeviceHandle::SubmitTransfer, | |
| 381 this, | |
| 382 transfer, | |
| 322 USB_TRANSFER_CONTROL, | 383 USB_TRANSFER_CONTROL, |
| 323 resized_buffer.get(), | 384 resized_buffer, |
| 324 resized_length, | 385 resized_length, |
| 325 callback); | 386 callback)); |
| 326 } | 387 } |
| 327 | 388 |
| 328 void UsbDeviceHandle::BulkTransfer(const UsbEndpointDirection direction, | 389 void UsbDeviceHandle::BulkTransfer(const UsbEndpointDirection direction, |
| 329 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, | 390 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, |
| 330 const unsigned int timeout, const UsbTransferCallback& callback) { | 391 const unsigned int timeout, const UsbTransferCallback& callback) { |
| 331 if (!handle_) { | 392 if (!device_) { |
| 332 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | 393 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); |
| 333 return; | 394 return; |
| 334 } | 395 } |
| 335 | 396 |
| 336 struct libusb_transfer* const transfer = libusb_alloc_transfer(0); | 397 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); |
| 337 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | 398 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; |
| 338 libusb_fill_bulk_transfer(transfer, handle_, new_endpoint, | 399 libusb_fill_bulk_transfer(transfer, handle_, new_endpoint, |
| 339 reinterpret_cast<uint8*>(buffer->data()), length, | 400 reinterpret_cast<uint8*>(buffer->data()), length, |
| 340 HandleTransferCompletion, this, timeout); | 401 PlatformTransferCompletionCallback, this, timeout); |
| 341 SubmitTransfer(transfer, USB_TRANSFER_BULK, buffer, length, callback); | 402 |
| 403 BrowserThread::PostTask( | |
| 404 BrowserThread::FILE, | |
| 405 FROM_HERE, | |
| 406 base::Bind(&UsbDeviceHandle::SubmitTransfer, | |
| 407 this, | |
| 408 transfer, | |
| 409 USB_TRANSFER_BULK, | |
| 410 make_scoped_refptr(buffer), | |
| 411 length, | |
| 412 callback)); | |
| 342 } | 413 } |
| 343 | 414 |
| 344 void UsbDeviceHandle::InterruptTransfer(const UsbEndpointDirection direction, | 415 void UsbDeviceHandle::InterruptTransfer(const UsbEndpointDirection direction, |
| 345 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, | 416 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, |
| 346 const unsigned int timeout, const UsbTransferCallback& callback) { | 417 const unsigned int timeout, const UsbTransferCallback& callback) { |
| 347 if (!handle_) { | 418 if (!device_) { |
| 348 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | 419 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); |
| 349 return; | 420 return; |
| 350 } | 421 } |
| 351 | 422 |
| 352 struct libusb_transfer* const transfer = libusb_alloc_transfer(0); | 423 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); |
| 353 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | 424 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; |
| 354 libusb_fill_interrupt_transfer(transfer, handle_, new_endpoint, | 425 libusb_fill_interrupt_transfer(transfer, handle_, new_endpoint, |
| 355 reinterpret_cast<uint8*>(buffer->data()), length, | 426 reinterpret_cast<uint8*>(buffer->data()), length, |
| 356 HandleTransferCompletion, this, timeout); | 427 PlatformTransferCompletionCallback, this, timeout); |
| 357 SubmitTransfer(transfer, USB_TRANSFER_INTERRUPT, buffer, length, callback); | 428 BrowserThread::PostTask( |
| 429 BrowserThread::FILE, | |
| 430 FROM_HERE, | |
| 431 base::Bind(&UsbDeviceHandle::SubmitTransfer, | |
| 432 this, | |
| 433 transfer, | |
| 434 USB_TRANSFER_INTERRUPT, | |
| 435 make_scoped_refptr(buffer), | |
| 436 length, | |
| 437 callback)); | |
| 358 } | 438 } |
| 359 | 439 |
| 360 void UsbDeviceHandle::IsochronousTransfer(const UsbEndpointDirection direction, | 440 void UsbDeviceHandle::IsochronousTransfer(const UsbEndpointDirection direction, |
| 361 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, | 441 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, |
| 362 const unsigned int packets, const unsigned int packet_length, | 442 const unsigned int packets, const unsigned int packet_length, |
| 363 const unsigned int timeout, const UsbTransferCallback& callback) { | 443 const unsigned int timeout, const UsbTransferCallback& callback) { |
| 364 if (!handle_) { | 444 if (!device_) { |
| 365 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | 445 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); |
| 366 return; | 446 return; |
| 367 } | 447 } |
| 368 | 448 |
| 369 const uint64 total_length = packets * packet_length; | 449 const uint64 total_length = packets * packet_length; |
| 370 CHECK(packets <= length && total_length <= length) << | 450 CHECK(packets <= length && total_length <= length) << |
| 371 "transfer length is too small"; | 451 "transfer length is too small"; |
| 372 | 452 |
| 373 struct libusb_transfer* const transfer = libusb_alloc_transfer(packets); | 453 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(packets); |
| 374 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | 454 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; |
| 375 libusb_fill_iso_transfer(transfer, handle_, new_endpoint, | 455 libusb_fill_iso_transfer(transfer, handle_, new_endpoint, |
| 376 reinterpret_cast<uint8*>(buffer->data()), length, packets, | 456 reinterpret_cast<uint8*>(buffer->data()), length, packets, |
| 377 HandleTransferCompletion, this, timeout); | 457 PlatformTransferCompletionCallback, this, timeout); |
| 378 libusb_set_iso_packet_lengths(transfer, packet_length); | 458 libusb_set_iso_packet_lengths(transfer, packet_length); |
| 379 | 459 |
| 380 SubmitTransfer(transfer, USB_TRANSFER_ISOCHRONOUS, buffer, length, callback); | 460 BrowserThread::PostTask( |
| 461 BrowserThread::FILE, | |
| 462 FROM_HERE, | |
| 463 base::Bind(&UsbDeviceHandle::SubmitTransfer, | |
| 464 this, | |
| 465 transfer, | |
| 466 USB_TRANSFER_ISOCHRONOUS, | |
| 467 make_scoped_refptr(buffer), | |
| 468 length, | |
| 469 callback)); | |
| 470 } | |
| 471 | |
| 472 void UsbDeviceHandle::RefreshEndpointMap() { | |
| 473 endpoint_map_.clear(); | |
| 474 for (ClaimedInterfaceMap::iterator it = claimed_interfaces_.begin(); | |
| 475 it != claimed_interfaces_.end(); ++it) { | |
| 476 scoped_refptr<const UsbInterfaceDescriptor> interface_desc = | |
| 477 interfaces_->GetInterface(it->first)->GetAltSetting( | |
| 478 it->second->alternate_setting()); | |
| 479 for (size_t i = 0; i < interface_desc->GetNumEndpoints(); i++) { | |
| 480 scoped_refptr<const UsbEndpointDescriptor> endpoint = | |
| 481 interface_desc->GetEndpoint(i); | |
| 482 endpoint_map_[endpoint->GetAddress()] = it->first; | |
| 483 } | |
| 484 } | |
| 381 } | 485 } |
| 382 | 486 |
| 383 void UsbDeviceHandle::SubmitTransfer(PlatformUsbTransferHandle handle, | 487 void UsbDeviceHandle::SubmitTransfer(PlatformUsbTransferHandle handle, |
| 384 UsbTransferType transfer_type, | 488 UsbTransferType transfer_type, |
| 385 net::IOBuffer* buffer, | 489 net::IOBuffer* buffer, |
| 386 const size_t length, | 490 const size_t length, |
| 387 const UsbTransferCallback& callback) { | 491 const UsbTransferCallback& callback) { |
| 492 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 493 | |
| 494 unsigned char address = handle->endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK; | |
| 495 if (!ContainsKey(endpoint_map_, address)) { | |
| 496 // Endpoint for given transfer not found or the interface is not claimed. | |
| 497 callback.Run(USB_TRANSFER_ERROR, buffer, 0); | |
| 498 return; | |
| 499 } | |
| 500 | |
| 388 Transfer transfer; | 501 Transfer transfer; |
| 389 transfer.transfer_type = transfer_type; | 502 transfer.transfer_type = transfer_type; |
| 390 transfer.buffer = buffer; | 503 transfer.buffer = buffer; |
| 391 transfer.length = length; | 504 transfer.length = length; |
| 392 transfer.callback = callback; | 505 transfer.callback = callback; |
| 506 transfer.claimed_interface = claimed_interfaces_[endpoint_map_[address]]; | |
| 393 | 507 |
| 394 { | 508 if (libusb_submit_transfer(handle) == LIBUSB_SUCCESS) { |
| 395 base::AutoLock lock(lock_); | |
| 396 transfers_[handle] = transfer; | 509 transfers_[handle] = transfer; |
| 397 } | 510 // Increases reference count. It will be decreased when transfer is |
| 398 if (libusb_submit_transfer(handle) != LIBUSB_SUCCESS) { | 511 // finished. |
| 399 base::AutoLock lock(lock_); | 512 AddRef(); |
|
pfeldman
2013/08/09 08:58:59
You should instead add scoped_refptr<UsbDeviceHand
Bei Zhang
2013/08/09 16:43:55
Done.
| |
| 400 transfers_.erase(handle); | 513 } else { |
| 401 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | 514 callback.Run(USB_TRANSFER_ERROR, buffer, 0); |
| 402 } | 515 } |
| 403 } | 516 } |
| 404 | 517 |
| 405 void UsbDeviceHandle::InternalClose() { | 518 void UsbDeviceHandle::InternalClose() { |
| 406 DCHECK(thread_checker_.CalledOnValidThread()); | 519 DCHECK(thread_checker_.CalledOnValidThread()); |
| 407 libusb_close(handle_); | 520 if (!device_) return; |
| 408 handle_ = NULL; | 521 |
| 522 // Cancel all the transfers. | |
| 523 for (TransferMap::iterator it = transfers_.begin(); | |
| 524 it != transfers_.end(); ++it) { | |
| 525 // The callback will be called some time later. | |
| 526 libusb_cancel_transfer(it->first); | |
| 527 } | |
| 528 | |
| 529 // Attempt-release all the interfaces. | |
| 530 // It will be retained until the transfer cancellation is finished. | |
| 531 claimed_interfaces_.clear(); | |
| 532 | |
| 533 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to | |
| 534 // finish. | |
| 409 device_ = NULL; | 535 device_ = NULL; |
| 410 } | 536 } |
| OLD | NEW |