OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "components/usb_service/usb_device_handle_impl.h" | |
6 | |
7 #include <algorithm> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/location.h" | |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/strings/string16.h" | |
15 #include "base/synchronization/lock.h" | |
16 #include "base/thread_task_runner_handle.h" | |
17 #include "components/usb_service/usb_context.h" | |
18 #include "components/usb_service/usb_device_impl.h" | |
19 #include "components/usb_service/usb_error.h" | |
20 #include "components/usb_service/usb_interface.h" | |
21 #include "components/usb_service/usb_service.h" | |
22 #include "third_party/libusb/src/libusb/libusb.h" | |
23 | |
24 namespace usb_service { | |
25 | |
26 typedef libusb_device* PlatformUsbDevice; | |
27 | |
28 void HandleTransferCompletion(usb_service::PlatformUsbTransferHandle transfer); | |
29 | |
30 namespace { | |
31 | |
32 static uint8 ConvertTransferDirection(const UsbEndpointDirection direction) { | |
33 switch (direction) { | |
34 case USB_DIRECTION_INBOUND: | |
35 return LIBUSB_ENDPOINT_IN; | |
36 case USB_DIRECTION_OUTBOUND: | |
37 return LIBUSB_ENDPOINT_OUT; | |
38 default: | |
39 NOTREACHED(); | |
40 return LIBUSB_ENDPOINT_IN; | |
41 } | |
42 } | |
43 | |
44 static uint8 CreateRequestType( | |
45 const UsbEndpointDirection direction, | |
46 const UsbDeviceHandle::TransferRequestType request_type, | |
47 const UsbDeviceHandle::TransferRecipient recipient) { | |
48 uint8 result = ConvertTransferDirection(direction); | |
49 | |
50 switch (request_type) { | |
51 case UsbDeviceHandle::STANDARD: | |
52 result |= LIBUSB_REQUEST_TYPE_STANDARD; | |
53 break; | |
54 case UsbDeviceHandle::CLASS: | |
55 result |= LIBUSB_REQUEST_TYPE_CLASS; | |
56 break; | |
57 case UsbDeviceHandle::VENDOR: | |
58 result |= LIBUSB_REQUEST_TYPE_VENDOR; | |
59 break; | |
60 case UsbDeviceHandle::RESERVED: | |
61 result |= LIBUSB_REQUEST_TYPE_RESERVED; | |
62 break; | |
63 } | |
64 | |
65 switch (recipient) { | |
66 case UsbDeviceHandle::DEVICE: | |
67 result |= LIBUSB_RECIPIENT_DEVICE; | |
68 break; | |
69 case UsbDeviceHandle::INTERFACE: | |
70 result |= LIBUSB_RECIPIENT_INTERFACE; | |
71 break; | |
72 case UsbDeviceHandle::ENDPOINT: | |
73 result |= LIBUSB_RECIPIENT_ENDPOINT; | |
74 break; | |
75 case UsbDeviceHandle::OTHER: | |
76 result |= LIBUSB_RECIPIENT_OTHER; | |
77 break; | |
78 } | |
79 | |
80 return result; | |
81 } | |
82 | |
83 static UsbTransferStatus ConvertTransferStatus( | |
84 const libusb_transfer_status status) { | |
85 switch (status) { | |
86 case LIBUSB_TRANSFER_COMPLETED: | |
87 return USB_TRANSFER_COMPLETED; | |
88 case LIBUSB_TRANSFER_ERROR: | |
89 return USB_TRANSFER_ERROR; | |
90 case LIBUSB_TRANSFER_TIMED_OUT: | |
91 return USB_TRANSFER_TIMEOUT; | |
92 case LIBUSB_TRANSFER_STALL: | |
93 return USB_TRANSFER_STALLED; | |
94 case LIBUSB_TRANSFER_NO_DEVICE: | |
95 return USB_TRANSFER_DISCONNECT; | |
96 case LIBUSB_TRANSFER_OVERFLOW: | |
97 return USB_TRANSFER_OVERFLOW; | |
98 case LIBUSB_TRANSFER_CANCELLED: | |
99 return USB_TRANSFER_CANCELLED; | |
100 default: | |
101 NOTREACHED(); | |
102 return USB_TRANSFER_ERROR; | |
103 } | |
104 } | |
105 | |
106 } // namespace | |
107 | |
108 class UsbDeviceHandleImpl::InterfaceClaimer | |
109 : public base::RefCountedThreadSafe<UsbDeviceHandleImpl::InterfaceClaimer> { | |
110 public: | |
111 InterfaceClaimer(const scoped_refptr<UsbDeviceHandleImpl> handle, | |
112 const int interface_number); | |
113 | |
114 bool Claim() const; | |
115 | |
116 int alternate_setting() const { return alternate_setting_; } | |
117 void set_alternate_setting(const int alternate_setting) { | |
118 alternate_setting_ = alternate_setting; | |
119 } | |
120 | |
121 private: | |
122 friend class UsbDevice; | |
123 friend class base::RefCountedThreadSafe<InterfaceClaimer>; | |
124 ~InterfaceClaimer(); | |
125 | |
126 const scoped_refptr<UsbDeviceHandleImpl> handle_; | |
127 const int interface_number_; | |
128 int alternate_setting_; | |
129 | |
130 DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer); | |
131 }; | |
132 | |
133 UsbDeviceHandleImpl::InterfaceClaimer::InterfaceClaimer( | |
134 const scoped_refptr<UsbDeviceHandleImpl> handle, | |
135 const int interface_number) | |
136 : handle_(handle), | |
137 interface_number_(interface_number), | |
138 alternate_setting_(0) { | |
139 } | |
140 | |
141 UsbDeviceHandleImpl::InterfaceClaimer::~InterfaceClaimer() { | |
142 libusb_release_interface(handle_->handle(), interface_number_); | |
143 } | |
144 | |
145 bool UsbDeviceHandleImpl::InterfaceClaimer::Claim() const { | |
146 const int rv = libusb_claim_interface(handle_->handle(), interface_number_); | |
147 if (rv != LIBUSB_SUCCESS) { | |
148 VLOG(1) << "Failed to claim interface: " << ConvertErrorToString(rv); | |
149 } | |
150 return rv == LIBUSB_SUCCESS; | |
151 } | |
152 | |
153 struct UsbDeviceHandleImpl::Transfer { | |
154 Transfer(); | |
155 ~Transfer(); | |
156 | |
157 void Complete(UsbTransferStatus status, size_t bytes_transferred); | |
158 | |
159 UsbTransferType transfer_type; | |
160 scoped_refptr<net::IOBuffer> buffer; | |
161 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface; | |
162 scoped_refptr<base::SingleThreadTaskRunner> task_runner; | |
163 size_t length; | |
164 UsbTransferCallback callback; | |
165 }; | |
166 | |
167 UsbDeviceHandleImpl::Transfer::Transfer() | |
168 : transfer_type(USB_TRANSFER_CONTROL), length(0) { | |
169 } | |
170 | |
171 UsbDeviceHandleImpl::Transfer::~Transfer() { | |
172 } | |
173 | |
174 void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status, | |
175 size_t bytes_transferred) { | |
176 if (task_runner->RunsTasksOnCurrentThread()) { | |
177 callback.Run(status, buffer, bytes_transferred); | |
178 } else { | |
179 task_runner->PostTask( | |
180 FROM_HERE, base::Bind(callback, status, buffer, bytes_transferred)); | |
181 } | |
182 } | |
183 | |
184 UsbDeviceHandleImpl::UsbDeviceHandleImpl( | |
185 scoped_refptr<UsbContext> context, | |
186 UsbDeviceImpl* device, | |
187 PlatformUsbDeviceHandle handle, | |
188 scoped_refptr<UsbConfigDescriptor> interfaces) | |
189 : device_(device), | |
190 handle_(handle), | |
191 interfaces_(interfaces), | |
192 context_(context), | |
193 task_runner_(base::ThreadTaskRunnerHandle::Get()) { | |
194 DCHECK(handle) << "Cannot create device with NULL handle."; | |
195 DCHECK(interfaces_.get()) << "Unable to list interfaces"; | |
196 } | |
197 | |
198 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() { | |
199 DCHECK(thread_checker_.CalledOnValidThread()); | |
200 | |
201 libusb_close(handle_); | |
202 handle_ = NULL; | |
203 } | |
204 | |
205 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const { | |
206 return static_cast<UsbDevice*>(device_); | |
207 } | |
208 | |
209 void UsbDeviceHandleImpl::Close() { | |
210 DCHECK(thread_checker_.CalledOnValidThread()); | |
211 if (device_) | |
212 device_->Close(this); | |
213 } | |
214 | |
215 /* static */ | |
216 void LIBUSB_CALL UsbDeviceHandleImpl::PlatformTransferCallback( | |
217 PlatformUsbTransferHandle transfer) { | |
218 UsbDeviceHandleImpl* device_handle = | |
219 reinterpret_cast<UsbDeviceHandleImpl*>(transfer->user_data); | |
220 device_handle->task_runner_->PostTask( | |
221 FROM_HERE, | |
222 base::Bind( | |
223 &UsbDeviceHandleImpl::CompleteTransfer, device_handle, transfer)); | |
224 } | |
225 | |
226 void UsbDeviceHandleImpl::CompleteTransfer(PlatformUsbTransferHandle handle) { | |
227 DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed"; | |
228 | |
229 Transfer transfer = transfers_[handle]; | |
230 transfers_.erase(handle); | |
231 | |
232 DCHECK_GE(handle->actual_length, 0) << "Negative actual length received"; | |
233 size_t actual_length = | |
234 static_cast<size_t>(std::max(handle->actual_length, 0)); | |
235 | |
236 DCHECK(transfer.length >= actual_length) | |
237 << "data too big for our buffer (libusb failure?)"; | |
238 | |
239 switch (transfer.transfer_type) { | |
240 case USB_TRANSFER_CONTROL: | |
241 // If the transfer is a control transfer we do not expose the control | |
242 // setup header to the caller. This logic strips off the header if | |
243 // present before invoking the callback provided with the transfer. | |
244 if (actual_length > 0) { | |
245 CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) | |
246 << "buffer was not correctly set: too small for the control header"; | |
247 | |
248 if (transfer.length >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) { | |
249 // If the payload is zero bytes long, pad out the allocated buffer | |
250 // size to one byte so that an IOBuffer of that size can be allocated. | |
251 scoped_refptr<net::IOBuffer> resized_buffer = | |
252 new net::IOBuffer(static_cast<int>( | |
253 std::max(actual_length, static_cast<size_t>(1)))); | |
254 memcpy(resized_buffer->data(), | |
255 transfer.buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, | |
256 actual_length); | |
257 transfer.buffer = resized_buffer; | |
258 } | |
259 } | |
260 break; | |
261 | |
262 case USB_TRANSFER_ISOCHRONOUS: | |
263 // Isochronous replies might carry data in the different isoc packets even | |
264 // if the transfer actual_data value is zero. Furthermore, not all of the | |
265 // received packets might contain data, so we need to calculate how many | |
266 // data bytes we are effectively providing and pack the results. | |
267 if (actual_length == 0) { | |
268 size_t packet_buffer_start = 0; | |
269 for (int i = 0; i < handle->num_iso_packets; ++i) { | |
270 PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i]; | |
271 if (packet->actual_length > 0) { | |
272 // We don't need to copy as long as all packets until now provide | |
273 // all the data the packet can hold. | |
274 if (actual_length < packet_buffer_start) { | |
275 CHECK(packet_buffer_start + packet->actual_length <= | |
276 transfer.length); | |
277 memmove(transfer.buffer->data() + actual_length, | |
278 transfer.buffer->data() + packet_buffer_start, | |
279 packet->actual_length); | |
280 } | |
281 actual_length += packet->actual_length; | |
282 } | |
283 | |
284 packet_buffer_start += packet->length; | |
285 } | |
286 } | |
287 break; | |
288 | |
289 case USB_TRANSFER_BULK: | |
290 case USB_TRANSFER_INTERRUPT: | |
291 break; | |
292 | |
293 default: | |
294 NOTREACHED() << "Invalid usb transfer type"; | |
295 break; | |
296 } | |
297 | |
298 transfer.Complete(ConvertTransferStatus(handle->status), actual_length); | |
299 libusb_free_transfer(handle); | |
300 | |
301 // Must release interface first before actually delete this. | |
302 transfer.claimed_interface = NULL; | |
303 } | |
304 | |
305 bool UsbDeviceHandleImpl::ClaimInterface(const int interface_number) { | |
306 DCHECK(thread_checker_.CalledOnValidThread()); | |
307 if (!device_) | |
308 return false; | |
309 if (ContainsKey(claimed_interfaces_, interface_number)) | |
310 return true; | |
311 | |
312 scoped_refptr<InterfaceClaimer> claimer = | |
313 new InterfaceClaimer(this, interface_number); | |
314 | |
315 if (claimer->Claim()) { | |
316 claimed_interfaces_[interface_number] = claimer; | |
317 RefreshEndpointMap(); | |
318 return true; | |
319 } | |
320 return false; | |
321 } | |
322 | |
323 bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number) { | |
324 DCHECK(thread_checker_.CalledOnValidThread()); | |
325 if (!device_) | |
326 return false; | |
327 if (!ContainsKey(claimed_interfaces_, interface_number)) | |
328 return false; | |
329 | |
330 // Cancel all the transfers on that interface. | |
331 InterfaceClaimer* interface_claimer = | |
332 claimed_interfaces_[interface_number].get(); | |
333 for (TransferMap::iterator it = transfers_.begin(); it != transfers_.end(); | |
334 ++it) { | |
335 if (it->second.claimed_interface.get() == interface_claimer) | |
336 libusb_cancel_transfer(it->first); | |
337 } | |
338 claimed_interfaces_.erase(interface_number); | |
339 | |
340 RefreshEndpointMap(); | |
341 return true; | |
342 } | |
343 | |
344 bool UsbDeviceHandleImpl::SetInterfaceAlternateSetting( | |
345 const int interface_number, | |
346 const int alternate_setting) { | |
347 DCHECK(thread_checker_.CalledOnValidThread()); | |
348 if (!device_) | |
349 return false; | |
350 if (!ContainsKey(claimed_interfaces_, interface_number)) | |
351 return false; | |
352 const int rv = libusb_set_interface_alt_setting( | |
353 handle_, interface_number, alternate_setting); | |
354 if (rv == LIBUSB_SUCCESS) { | |
355 claimed_interfaces_[interface_number]->set_alternate_setting( | |
356 alternate_setting); | |
357 RefreshEndpointMap(); | |
358 } else { | |
359 VLOG(1) << "Failed to set interface (" << interface_number << ", " | |
360 << alternate_setting << "): " << ConvertErrorToString(rv); | |
361 } | |
362 return rv == LIBUSB_SUCCESS; | |
363 } | |
364 | |
365 bool UsbDeviceHandleImpl::ResetDevice() { | |
366 DCHECK(thread_checker_.CalledOnValidThread()); | |
367 if (!device_) | |
368 return false; | |
369 | |
370 const int rv = libusb_reset_device(handle_); | |
371 if (rv != LIBUSB_SUCCESS) { | |
372 VLOG(1) << "Failed to reset device: " << ConvertErrorToString(rv); | |
373 } | |
374 return rv == LIBUSB_SUCCESS; | |
375 } | |
376 | |
377 bool UsbDeviceHandleImpl::GetSupportedLanguages() { | |
378 if (!languages_.empty()) { | |
379 return true; | |
380 } | |
381 | |
382 // The 1-byte length field limits the descriptor to 256-bytes (128 uint16s). | |
383 uint16 languages[128]; | |
384 int size = libusb_get_string_descriptor( | |
385 handle_, | |
386 0, | |
387 0, | |
388 reinterpret_cast<unsigned char*>(&languages[0]), | |
389 sizeof(languages)); | |
390 if (size < 0) { | |
391 VLOG(1) << "Failed to get list of supported languages: " | |
392 << ConvertErrorToString(size); | |
393 return false; | |
394 } else if (size < 2) { | |
395 VLOG(1) << "String descriptor zero has no header."; | |
396 return false; | |
397 // The first 2 bytes of the descriptor are the total length and type tag. | |
398 } else if ((languages[0] & 0xff) != size) { | |
399 VLOG(1) << "String descriptor zero size mismatch: " << (languages[0] & 0xff) | |
400 << " != " << size; | |
401 return false; | |
402 } else if ((languages[0] >> 8) != LIBUSB_DT_STRING) { | |
403 VLOG(1) << "String descriptor zero is not a string descriptor."; | |
404 return false; | |
405 } | |
406 | |
407 languages_.assign(languages[1], languages[(size - 2) / 2]); | |
408 return true; | |
409 } | |
410 | |
411 bool UsbDeviceHandleImpl::GetStringDescriptor(uint8 string_id, | |
412 base::string16* string) { | |
413 if (!GetSupportedLanguages()) { | |
414 return false; | |
415 } | |
416 | |
417 std::map<uint8, base::string16>::const_iterator it = strings_.find(string_id); | |
418 if (it != strings_.end()) { | |
419 *string = it->second; | |
420 return true; | |
421 } | |
422 | |
423 for (size_t i = 0; i < languages_.size(); ++i) { | |
424 // Get the string using language ID. | |
425 uint16 language_id = languages_[i]; | |
426 // The 1-byte length field limits the descriptor to 256-bytes (128 char16s). | |
427 base::char16 text[128]; | |
428 int size = | |
429 libusb_get_string_descriptor(handle_, | |
430 string_id, | |
431 language_id, | |
432 reinterpret_cast<unsigned char*>(&text[0]), | |
433 sizeof(text)); | |
434 if (size < 0) { | |
435 VLOG(1) << "Failed to get string descriptor " << string_id << " (langid " | |
436 << language_id << "): " << ConvertErrorToString(size); | |
437 continue; | |
438 } else if (size < 2) { | |
439 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id | |
440 << ") has no header."; | |
441 continue; | |
442 // The first 2 bytes of the descriptor are the total length and type tag. | |
443 } else if ((text[0] & 0xff) != size) { | |
444 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id | |
445 << ") size mismatch: " << (text[0] & 0xff) << " != " << size; | |
446 continue; | |
447 } else if ((text[0] >> 8) != LIBUSB_DT_STRING) { | |
448 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id | |
449 << ") is not a string descriptor."; | |
450 continue; | |
451 } | |
452 | |
453 *string = base::string16(text + 1, (size - 2) / 2); | |
454 strings_[string_id] = *string; | |
455 return true; | |
456 } | |
457 | |
458 return false; | |
459 } | |
460 | |
461 bool UsbDeviceHandleImpl::GetManufacturer(base::string16* manufacturer) { | |
462 DCHECK(thread_checker_.CalledOnValidThread()); | |
463 PlatformUsbDevice device = libusb_get_device(handle_); | |
464 libusb_device_descriptor desc; | |
465 | |
466 // This is a non-blocking call as libusb has the descriptor in memory. | |
467 const int rv = libusb_get_device_descriptor(device, &desc); | |
468 if (rv != LIBUSB_SUCCESS) { | |
469 VLOG(1) << "Failed to read device descriptor: " << ConvertErrorToString(rv); | |
470 return false; | |
471 } | |
472 | |
473 if (desc.iManufacturer == 0) { | |
474 return false; | |
475 } | |
476 | |
477 return GetStringDescriptor(desc.iManufacturer, manufacturer); | |
478 } | |
479 | |
480 bool UsbDeviceHandleImpl::GetProduct(base::string16* product) { | |
481 DCHECK(thread_checker_.CalledOnValidThread()); | |
482 PlatformUsbDevice device = libusb_get_device(handle_); | |
483 libusb_device_descriptor desc; | |
484 | |
485 // This is a non-blocking call as libusb has the descriptor in memory. | |
486 const int rv = libusb_get_device_descriptor(device, &desc); | |
487 if (rv != LIBUSB_SUCCESS) { | |
488 VLOG(1) << "Failed to read device descriptor: " << ConvertErrorToString(rv); | |
489 return false; | |
490 } | |
491 | |
492 if (desc.iProduct == 0) { | |
493 return false; | |
494 } | |
495 | |
496 return GetStringDescriptor(desc.iProduct, product); | |
497 } | |
498 | |
499 bool UsbDeviceHandleImpl::GetSerial(base::string16* serial) { | |
500 DCHECK(thread_checker_.CalledOnValidThread()); | |
501 PlatformUsbDevice device = libusb_get_device(handle_); | |
502 libusb_device_descriptor desc; | |
503 | |
504 // This is a non-blocking call as libusb has the descriptor in memory. | |
505 const int rv = libusb_get_device_descriptor(device, &desc); | |
506 if (rv != LIBUSB_SUCCESS) { | |
507 VLOG(1) << "Failed to read device descriptor: " << ConvertErrorToString(rv); | |
508 return false; | |
509 } | |
510 | |
511 if (desc.iSerialNumber == 0) { | |
512 return false; | |
513 } | |
514 | |
515 return GetStringDescriptor(desc.iSerialNumber, serial); | |
516 } | |
517 | |
518 void UsbDeviceHandleImpl::ControlTransfer( | |
519 const UsbEndpointDirection direction, | |
520 const TransferRequestType request_type, | |
521 const TransferRecipient recipient, | |
522 const uint8 request, | |
523 const uint16 value, | |
524 const uint16 index, | |
525 net::IOBuffer* buffer, | |
526 const size_t length, | |
527 const unsigned int timeout, | |
528 const UsbTransferCallback& callback) { | |
529 if (!device_) { | |
530 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | |
531 return; | |
532 } | |
533 | |
534 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length; | |
535 scoped_refptr<net::IOBuffer> resized_buffer( | |
536 new net::IOBufferWithSize(static_cast<int>(resized_length))); | |
537 if (!resized_buffer.get()) { | |
538 callback.Run(USB_TRANSFER_ERROR, buffer, 0); | |
539 return; | |
540 } | |
541 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, | |
542 buffer->data(), | |
543 static_cast<int>(length)); | |
544 | |
545 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); | |
546 const uint8 converted_type = | |
547 CreateRequestType(direction, request_type, recipient); | |
548 libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()), | |
549 converted_type, | |
550 request, | |
551 value, | |
552 index, | |
553 static_cast<int16>(length)); | |
554 libusb_fill_control_transfer(transfer, | |
555 handle_, | |
556 reinterpret_cast<uint8*>(resized_buffer->data()), | |
557 &UsbDeviceHandleImpl::PlatformTransferCallback, | |
558 this, | |
559 timeout); | |
560 | |
561 PostOrSubmitTransfer( | |
562 transfer, USB_TRANSFER_CONTROL, resized_buffer, resized_length, callback); | |
563 } | |
564 | |
565 void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction, | |
566 const uint8 endpoint, | |
567 net::IOBuffer* buffer, | |
568 const size_t length, | |
569 const unsigned int timeout, | |
570 const UsbTransferCallback& callback) { | |
571 if (!device_) { | |
572 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | |
573 return; | |
574 } | |
575 | |
576 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); | |
577 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | |
578 libusb_fill_bulk_transfer(transfer, | |
579 handle_, | |
580 new_endpoint, | |
581 reinterpret_cast<uint8*>(buffer->data()), | |
582 static_cast<int>(length), | |
583 &UsbDeviceHandleImpl::PlatformTransferCallback, | |
584 this, | |
585 timeout); | |
586 | |
587 PostOrSubmitTransfer(transfer, USB_TRANSFER_BULK, buffer, length, callback); | |
588 } | |
589 | |
590 void UsbDeviceHandleImpl::InterruptTransfer( | |
591 const UsbEndpointDirection direction, | |
592 const uint8 endpoint, | |
593 net::IOBuffer* buffer, | |
594 const size_t length, | |
595 const unsigned int timeout, | |
596 const UsbTransferCallback& callback) { | |
597 if (!device_) { | |
598 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | |
599 return; | |
600 } | |
601 | |
602 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); | |
603 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | |
604 libusb_fill_interrupt_transfer(transfer, | |
605 handle_, | |
606 new_endpoint, | |
607 reinterpret_cast<uint8*>(buffer->data()), | |
608 static_cast<int>(length), | |
609 &UsbDeviceHandleImpl::PlatformTransferCallback, | |
610 this, | |
611 timeout); | |
612 | |
613 PostOrSubmitTransfer( | |
614 transfer, USB_TRANSFER_INTERRUPT, buffer, length, callback); | |
615 } | |
616 | |
617 void UsbDeviceHandleImpl::IsochronousTransfer( | |
618 const UsbEndpointDirection direction, | |
619 const uint8 endpoint, | |
620 net::IOBuffer* buffer, | |
621 const size_t length, | |
622 const unsigned int packets, | |
623 const unsigned int packet_length, | |
624 const unsigned int timeout, | |
625 const UsbTransferCallback& callback) { | |
626 if (!device_) { | |
627 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | |
628 return; | |
629 } | |
630 | |
631 const uint64 total_length = packets * packet_length; | |
632 CHECK(packets <= length && total_length <= length) | |
633 << "transfer length is too small"; | |
634 | |
635 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(packets); | |
636 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | |
637 libusb_fill_iso_transfer(transfer, | |
638 handle_, | |
639 new_endpoint, | |
640 reinterpret_cast<uint8*>(buffer->data()), | |
641 static_cast<int>(length), | |
642 packets, | |
643 &UsbDeviceHandleImpl::PlatformTransferCallback, | |
644 this, | |
645 timeout); | |
646 libusb_set_iso_packet_lengths(transfer, packet_length); | |
647 | |
648 PostOrSubmitTransfer( | |
649 transfer, USB_TRANSFER_ISOCHRONOUS, buffer, length, callback); | |
650 } | |
651 | |
652 void UsbDeviceHandleImpl::RefreshEndpointMap() { | |
653 DCHECK(thread_checker_.CalledOnValidThread()); | |
654 endpoint_map_.clear(); | |
655 for (ClaimedInterfaceMap::iterator it = claimed_interfaces_.begin(); | |
656 it != claimed_interfaces_.end(); | |
657 ++it) { | |
658 scoped_refptr<const UsbInterfaceAltSettingDescriptor> interface_desc = | |
659 interfaces_->GetInterface(it->first) | |
660 ->GetAltSetting(it->second->alternate_setting()); | |
661 for (size_t i = 0; i < interface_desc->GetNumEndpoints(); i++) { | |
662 scoped_refptr<const UsbEndpointDescriptor> endpoint = | |
663 interface_desc->GetEndpoint(i); | |
664 endpoint_map_[endpoint->GetAddress()] = it->first; | |
665 } | |
666 } | |
667 } | |
668 | |
669 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> | |
670 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) { | |
671 unsigned char address = endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK; | |
672 if (ContainsKey(endpoint_map_, address)) | |
673 return claimed_interfaces_[endpoint_map_[address]]; | |
674 return NULL; | |
675 } | |
676 | |
677 void UsbDeviceHandleImpl::PostOrSubmitTransfer( | |
678 PlatformUsbTransferHandle transfer, | |
679 UsbTransferType transfer_type, | |
680 net::IOBuffer* buffer, | |
681 size_t length, | |
682 const UsbTransferCallback& callback) { | |
683 if (task_runner_->RunsTasksOnCurrentThread()) { | |
684 SubmitTransfer(transfer, | |
685 transfer_type, | |
686 buffer, | |
687 length, | |
688 base::ThreadTaskRunnerHandle::Get(), | |
689 callback); | |
690 } else { | |
691 task_runner_->PostTask(FROM_HERE, | |
692 base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, | |
693 this, | |
694 transfer, | |
695 transfer_type, | |
696 make_scoped_refptr(buffer), | |
697 length, | |
698 base::ThreadTaskRunnerHandle::Get(), | |
699 callback)); | |
700 } | |
701 } | |
702 | |
703 void UsbDeviceHandleImpl::SubmitTransfer( | |
704 PlatformUsbTransferHandle handle, | |
705 UsbTransferType transfer_type, | |
706 net::IOBuffer* buffer, | |
707 const size_t length, | |
708 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
709 const UsbTransferCallback& callback) { | |
710 DCHECK(thread_checker_.CalledOnValidThread()); | |
711 | |
712 Transfer transfer; | |
713 transfer.transfer_type = transfer_type; | |
714 transfer.buffer = buffer; | |
715 transfer.length = length; | |
716 transfer.callback = callback; | |
717 transfer.task_runner = task_runner; | |
718 | |
719 if (!device_) { | |
720 transfer.Complete(USB_TRANSFER_DISCONNECT, 0); | |
721 return; | |
722 } | |
723 | |
724 // It's OK for this method to return NULL. libusb_submit_transfer will fail if | |
725 // it requires an interface we didn't claim. | |
726 transfer.claimed_interface = GetClaimedInterfaceForEndpoint(handle->endpoint); | |
727 | |
728 const int rv = libusb_submit_transfer(handle); | |
729 if (rv == LIBUSB_SUCCESS) { | |
730 transfers_[handle] = transfer; | |
731 } else { | |
732 VLOG(1) << "Failed to submit transfer: " << ConvertErrorToString(rv); | |
733 transfer.Complete(USB_TRANSFER_ERROR, 0); | |
734 } | |
735 } | |
736 | |
737 void UsbDeviceHandleImpl::InternalClose() { | |
738 DCHECK(thread_checker_.CalledOnValidThread()); | |
739 if (!device_) | |
740 return; | |
741 | |
742 // Cancel all the transfers. | |
743 for (TransferMap::iterator it = transfers_.begin(); it != transfers_.end(); | |
744 ++it) { | |
745 // The callback will be called some time later. | |
746 libusb_cancel_transfer(it->first); | |
747 } | |
748 | |
749 // Attempt-release all the interfaces. | |
750 // It will be retained until the transfer cancellation is finished. | |
751 claimed_interfaces_.clear(); | |
752 | |
753 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to | |
754 // finish. | |
755 device_ = NULL; | |
756 } | |
757 | |
758 } // namespace usb_service | |
OLD | NEW |