Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / usb / usb_device_handle.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/usb/usb_device_handle.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "base/message_loop/message_loop.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string16.h"
13 #include "base/synchronization/lock.h"
14 #include "chrome/browser/usb/usb_context.h"
15 #include "chrome/browser/usb/usb_device.h"
16 #include "chrome/browser/usb/usb_interface.h"
17 #include "chrome/browser/usb/usb_service.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "third_party/libusb/src/libusb/libusb.h"
20
21 using content::BrowserThread;
22 void HandleTransferCompletion(PlatformUsbTransferHandle transfer);
23
24 namespace {
25
26 static uint8 ConvertTransferDirection(
27     const UsbEndpointDirection direction) {
28   switch (direction) {
29     case USB_DIRECTION_INBOUND:
30       return LIBUSB_ENDPOINT_IN;
31     case USB_DIRECTION_OUTBOUND:
32       return LIBUSB_ENDPOINT_OUT;
33     default:
34       NOTREACHED();
35       return LIBUSB_ENDPOINT_IN;
36   }
37 }
38
39 static uint8 CreateRequestType(const UsbEndpointDirection direction,
40     const UsbDeviceHandle::TransferRequestType request_type,
41     const UsbDeviceHandle::TransferRecipient recipient) {
42   uint8 result = ConvertTransferDirection(direction);
43
44   switch (request_type) {
45     case UsbDeviceHandle::STANDARD:
46       result |= LIBUSB_REQUEST_TYPE_STANDARD;
47       break;
48     case UsbDeviceHandle::CLASS:
49       result |= LIBUSB_REQUEST_TYPE_CLASS;
50       break;
51     case UsbDeviceHandle::VENDOR:
52       result |= LIBUSB_REQUEST_TYPE_VENDOR;
53       break;
54     case UsbDeviceHandle::RESERVED:
55       result |= LIBUSB_REQUEST_TYPE_RESERVED;
56       break;
57   }
58
59   switch (recipient) {
60     case UsbDeviceHandle::DEVICE:
61       result |= LIBUSB_RECIPIENT_DEVICE;
62       break;
63     case UsbDeviceHandle::INTERFACE:
64       result |= LIBUSB_RECIPIENT_INTERFACE;
65       break;
66     case UsbDeviceHandle::ENDPOINT:
67       result |= LIBUSB_RECIPIENT_ENDPOINT;
68       break;
69     case UsbDeviceHandle::OTHER:
70       result |= LIBUSB_RECIPIENT_OTHER;
71       break;
72   }
73
74   return result;
75 }
76
77 static UsbTransferStatus ConvertTransferStatus(
78     const libusb_transfer_status status) {
79   switch (status) {
80     case LIBUSB_TRANSFER_COMPLETED:
81       return USB_TRANSFER_COMPLETED;
82     case LIBUSB_TRANSFER_ERROR:
83       return USB_TRANSFER_ERROR;
84     case LIBUSB_TRANSFER_TIMED_OUT:
85       return USB_TRANSFER_TIMEOUT;
86     case LIBUSB_TRANSFER_STALL:
87       return USB_TRANSFER_STALLED;
88     case LIBUSB_TRANSFER_NO_DEVICE:
89       return USB_TRANSFER_DISCONNECT;
90     case LIBUSB_TRANSFER_OVERFLOW:
91       return USB_TRANSFER_OVERFLOW;
92     case LIBUSB_TRANSFER_CANCELLED:
93       return USB_TRANSFER_CANCELLED;
94     default:
95       NOTREACHED();
96       return USB_TRANSFER_ERROR;
97   }
98 }
99
100 static void LIBUSB_CALL PlatformTransferCompletionCallback(
101     PlatformUsbTransferHandle transfer) {
102   BrowserThread::PostTask(BrowserThread::FILE,
103                           FROM_HERE,
104                           base::Bind(HandleTransferCompletion, transfer));
105 }
106
107 }  // namespace
108
109 void HandleTransferCompletion(PlatformUsbTransferHandle transfer) {
110   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
111   UsbDeviceHandle* const device_handle =
112       reinterpret_cast<UsbDeviceHandle*>(transfer->user_data);
113   CHECK(device_handle) << "Device handle is closed before transfer finishes.";
114   device_handle->TransferComplete(transfer);
115   libusb_free_transfer(transfer);
116 }
117
118
119 class UsbDeviceHandle::InterfaceClaimer
120     : public base::RefCountedThreadSafe<UsbDeviceHandle::InterfaceClaimer> {
121  public:
122   InterfaceClaimer(const scoped_refptr<UsbDeviceHandle> handle,
123                    const int interface_number);
124
125   bool Claim() const;
126
127   int alternate_setting() const { return alternate_setting_; }
128   void set_alternate_setting(const int alternate_setting) {
129     alternate_setting_ = alternate_setting;
130   }
131
132  private:
133   friend class UsbDevice;
134   friend class base::RefCountedThreadSafe<InterfaceClaimer>;
135   ~InterfaceClaimer();
136
137   const scoped_refptr<UsbDeviceHandle> handle_;
138   const int interface_number_;
139   int alternate_setting_;
140
141   DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer);
142 };
143
144 UsbDeviceHandle::InterfaceClaimer::InterfaceClaimer(
145     const scoped_refptr<UsbDeviceHandle> handle, const int interface_number)
146     : handle_(handle),
147       interface_number_(interface_number),
148       alternate_setting_(0) {
149 }
150
151 UsbDeviceHandle::InterfaceClaimer::~InterfaceClaimer() {
152   libusb_release_interface(handle_->handle(), interface_number_);
153 }
154
155 bool UsbDeviceHandle::InterfaceClaimer::Claim() const {
156   return libusb_claim_interface(handle_->handle(), interface_number_) == 0;
157 }
158
159 struct UsbDeviceHandle::Transfer {
160   Transfer();
161   ~Transfer();
162
163   UsbTransferType transfer_type;
164   scoped_refptr<net::IOBuffer> buffer;
165   scoped_refptr<UsbDeviceHandle::InterfaceClaimer> claimed_interface;
166   scoped_refptr<base::MessageLoopProxy> message_loop_proxy;
167   size_t length;
168   UsbTransferCallback callback;
169 };
170
171 UsbDeviceHandle::Transfer::Transfer()
172     : transfer_type(USB_TRANSFER_CONTROL),
173       length(0) {
174 }
175
176 UsbDeviceHandle::Transfer::~Transfer() {}
177
178 UsbDeviceHandle::UsbDeviceHandle(
179     scoped_refptr<UsbContext> context,
180     UsbDevice* device,
181     PlatformUsbDeviceHandle handle,
182     scoped_refptr<UsbConfigDescriptor> interfaces)
183     : device_(device),
184       handle_(handle),
185       interfaces_(interfaces),
186       context_(context) {
187   DCHECK(thread_checker_.CalledOnValidThread());
188   DCHECK(handle) << "Cannot create device with NULL handle.";
189   DCHECK(interfaces_) << "Unabled to list interfaces";
190 }
191
192 UsbDeviceHandle::UsbDeviceHandle() : device_(NULL), handle_(NULL) {
193 }
194
195 UsbDeviceHandle::~UsbDeviceHandle() {
196   DCHECK(thread_checker_.CalledOnValidThread());
197
198   libusb_close(handle_);
199   handle_ = NULL;
200 }
201
202 scoped_refptr<UsbDevice> UsbDeviceHandle::device() const {
203   return device_;
204 }
205
206 void UsbDeviceHandle::Close() {
207   DCHECK(thread_checker_.CalledOnValidThread());
208   if (device_)
209     device_->Close(this);
210 }
211
212 void UsbDeviceHandle::TransferComplete(PlatformUsbTransferHandle handle) {
213   DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed";
214
215   Transfer transfer = transfers_[handle];
216   transfers_.erase(handle);
217
218   DCHECK_GE(handle->actual_length, 0) << "Negative actual length received";
219   size_t actual_length =
220       static_cast<size_t>(std::max(handle->actual_length, 0));
221
222   DCHECK(transfer.length >= actual_length) <<
223       "data too big for our buffer (libusb failure?)";
224
225   scoped_refptr<net::IOBuffer> buffer = transfer.buffer;
226   switch (transfer.transfer_type) {
227     case USB_TRANSFER_CONTROL:
228       // If the transfer is a control transfer we do not expose the control
229       // setup header to the caller. This logic strips off the header if
230       // present before invoking the callback provided with the transfer.
231       if (actual_length > 0) {
232         CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) <<
233             "buffer was not correctly set: too small for the control header";
234
235         if (transfer.length >= actual_length &&
236             actual_length >= LIBUSB_CONTROL_SETUP_SIZE) {
237           // If the payload is zero bytes long, pad out the allocated buffer
238           // size to one byte so that an IOBuffer of that size can be allocated.
239           scoped_refptr<net::IOBuffer> resized_buffer = new net::IOBuffer(
240               std::max(actual_length, static_cast<size_t>(1)));
241           memcpy(resized_buffer->data(),
242                  buffer->data() + LIBUSB_CONTROL_SETUP_SIZE,
243                  actual_length);
244           buffer = resized_buffer;
245         }
246       }
247       break;
248
249     case USB_TRANSFER_ISOCHRONOUS:
250       // Isochronous replies might carry data in the different isoc packets even
251       // if the transfer actual_data value is zero. Furthermore, not all of the
252       // received packets might contain data, so we need to calculate how many
253       // data bytes we are effectively providing and pack the results.
254       if (actual_length == 0) {
255         size_t packet_buffer_start = 0;
256         for (int i = 0; i < handle->num_iso_packets; ++i) {
257           PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i];
258           if (packet->actual_length > 0) {
259             // We don't need to copy as long as all packets until now provide
260             // all the data the packet can hold.
261             if (actual_length < packet_buffer_start) {
262               CHECK(packet_buffer_start + packet->actual_length <=
263                     transfer.length);
264               memmove(buffer->data() + actual_length,
265                       buffer->data() + packet_buffer_start,
266                       packet->actual_length);
267             }
268             actual_length += packet->actual_length;
269           }
270
271           packet_buffer_start += packet->length;
272         }
273       }
274       break;
275
276     case USB_TRANSFER_BULK:
277     case USB_TRANSFER_INTERRUPT:
278       break;
279
280     default:
281       NOTREACHED() << "Invalid usb transfer type";
282       break;
283   }
284
285   transfer.message_loop_proxy->PostTask(
286       FROM_HERE,
287       base::Bind(transfer.callback,
288                  ConvertTransferStatus(handle->status),
289                  buffer,
290                  actual_length));
291
292   // Must release interface first before actually delete this.
293   transfer.claimed_interface = NULL;
294 }
295
296 bool UsbDeviceHandle::ClaimInterface(const int interface_number) {
297   DCHECK(thread_checker_.CalledOnValidThread());
298   if (!device_) return false;
299   if (ContainsKey(claimed_interfaces_, interface_number)) return true;
300
301   scoped_refptr<InterfaceClaimer> claimer =
302       new InterfaceClaimer(this, interface_number);
303
304   if (claimer->Claim()) {
305     claimed_interfaces_[interface_number]= claimer;
306     RefreshEndpointMap();
307     return true;
308   }
309   return false;
310 }
311
312 bool UsbDeviceHandle::ReleaseInterface(const int interface_number) {
313   DCHECK(thread_checker_.CalledOnValidThread());
314   if (!device_) return false;
315   if (!ContainsKey(claimed_interfaces_, interface_number)) return false;
316
317   // Cancel all the transfers on that interface.
318   InterfaceClaimer* interface_claimer =
319       claimed_interfaces_[interface_number].get();
320   for (TransferMap::iterator it = transfers_.begin();
321       it != transfers_.end(); ++it) {
322     if (it->second.claimed_interface.get() == interface_claimer)
323       libusb_cancel_transfer(it->first);
324   }
325   claimed_interfaces_.erase(interface_number);
326
327   RefreshEndpointMap();
328   return true;
329 }
330
331 bool UsbDeviceHandle::SetInterfaceAlternateSetting(
332     const int interface_number,
333     const int alternate_setting) {
334   DCHECK(thread_checker_.CalledOnValidThread());
335   if (!device_) return false;
336   if (!ContainsKey(claimed_interfaces_, interface_number)) return false;
337   const int rv = libusb_set_interface_alt_setting(handle_,
338       interface_number, alternate_setting);
339   if (rv == 0) {
340     claimed_interfaces_[interface_number]->
341       set_alternate_setting(alternate_setting);
342     RefreshEndpointMap();
343     return true;
344   }
345   return false;
346 }
347
348 bool UsbDeviceHandle::ResetDevice() {
349   DCHECK(thread_checker_.CalledOnValidThread());
350   if (!device_) return false;
351
352   return libusb_reset_device(handle_) == 0;
353 }
354
355 bool UsbDeviceHandle::GetSerial(base::string16* serial) {
356   DCHECK(thread_checker_.CalledOnValidThread());
357   PlatformUsbDevice device = libusb_get_device(handle_);
358   libusb_device_descriptor desc;
359
360   if (libusb_get_device_descriptor(device, &desc) != LIBUSB_SUCCESS)
361     return false;
362
363   if (desc.iSerialNumber == 0)
364     return false;
365
366   // Getting supported language ID.
367   uint16 langid[128] = { 0 };
368
369   int size = libusb_get_string_descriptor(
370       handle_, 0, 0,
371       reinterpret_cast<unsigned char*>(&langid[0]), sizeof(langid));
372   if (size < 0)
373     return false;
374
375   int language_count = (size - 2) / 2;
376
377   for (int i = 1; i <= language_count; ++i) {
378     // Get the string using language ID.
379     base::char16 text[256] = { 0 };
380     size = libusb_get_string_descriptor(
381         handle_, desc.iSerialNumber, langid[i],
382         reinterpret_cast<unsigned char*>(&text[0]), sizeof(text));
383     if (size <= 2)
384       continue;
385     if ((text[0] >> 8) != LIBUSB_DT_STRING)
386       continue;
387     if ((text[0] & 255) > size)
388       continue;
389
390     size = size / 2 - 1;
391     *serial = base::string16(text + 1, size);
392     return true;
393   }
394   return false;
395 }
396
397 void UsbDeviceHandle::ControlTransfer(const UsbEndpointDirection direction,
398     const TransferRequestType request_type, const TransferRecipient recipient,
399     const uint8 request, const uint16 value, const uint16 index,
400     net::IOBuffer* buffer, const size_t length, const unsigned int timeout,
401     const UsbTransferCallback& callback) {
402   if (!device_) {
403     callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
404     return;
405   }
406
407   const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
408   scoped_refptr<net::IOBuffer> resized_buffer(new net::IOBufferWithSize(
409       resized_length));
410   memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
411          length);
412
413   PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
414   const uint8 converted_type = CreateRequestType(direction, request_type,
415                                                  recipient);
416   libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()),
417                             converted_type, request, value, index, length);
418   libusb_fill_control_transfer(
419       transfer,
420       handle_,
421       reinterpret_cast<uint8*>(resized_buffer->data()),
422       PlatformTransferCompletionCallback,
423       this,
424       timeout);
425
426   BrowserThread::PostTask(
427       BrowserThread::FILE,
428       FROM_HERE,
429       base::Bind(&UsbDeviceHandle::SubmitTransfer,
430                  this,
431                  transfer,
432                  USB_TRANSFER_CONTROL,
433                  resized_buffer,
434                  resized_length,
435                  base::MessageLoopProxy::current(),
436                  callback));
437 }
438
439 void UsbDeviceHandle::BulkTransfer(const UsbEndpointDirection direction,
440     const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
441     const unsigned int timeout, const UsbTransferCallback& callback) {
442   if (!device_) {
443     callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
444     return;
445   }
446
447   PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
448   const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
449   libusb_fill_bulk_transfer(transfer, handle_, new_endpoint,
450       reinterpret_cast<uint8*>(buffer->data()), length,
451       PlatformTransferCompletionCallback, this, timeout);
452
453   BrowserThread::PostTask(
454       BrowserThread::FILE,
455       FROM_HERE,
456       base::Bind(&UsbDeviceHandle::SubmitTransfer,
457                  this,
458                  transfer,
459                  USB_TRANSFER_BULK,
460                  make_scoped_refptr(buffer),
461                  length,
462                  base::MessageLoopProxy::current(),
463                  callback));
464 }
465
466 void UsbDeviceHandle::InterruptTransfer(const UsbEndpointDirection direction,
467     const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
468     const unsigned int timeout, const UsbTransferCallback& callback) {
469   if (!device_) {
470     callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
471     return;
472   }
473
474   PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
475   const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
476   libusb_fill_interrupt_transfer(transfer, handle_, new_endpoint,
477       reinterpret_cast<uint8*>(buffer->data()), length,
478       PlatformTransferCompletionCallback, this, timeout);
479   BrowserThread::PostTask(
480       BrowserThread::FILE,
481       FROM_HERE,
482       base::Bind(&UsbDeviceHandle::SubmitTransfer,
483                  this,
484                  transfer,
485                  USB_TRANSFER_INTERRUPT,
486                  make_scoped_refptr(buffer),
487                  length,
488                  base::MessageLoopProxy::current(),
489                  callback));
490 }
491
492 void UsbDeviceHandle::IsochronousTransfer(const UsbEndpointDirection direction,
493     const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
494     const unsigned int packets, const unsigned int packet_length,
495     const unsigned int timeout, const UsbTransferCallback& callback) {
496   if (!device_) {
497     callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
498     return;
499   }
500
501   const uint64 total_length = packets * packet_length;
502   CHECK(packets <= length && total_length <= length) <<
503       "transfer length is too small";
504
505   PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(packets);
506   const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
507   libusb_fill_iso_transfer(transfer, handle_, new_endpoint,
508       reinterpret_cast<uint8*>(buffer->data()), length, packets,
509       PlatformTransferCompletionCallback, this, timeout);
510   libusb_set_iso_packet_lengths(transfer, packet_length);
511
512   BrowserThread::PostTask(
513       BrowserThread::FILE,
514       FROM_HERE,
515       base::Bind(&UsbDeviceHandle::SubmitTransfer,
516                  this,
517                  transfer,
518                  USB_TRANSFER_ISOCHRONOUS,
519                  make_scoped_refptr(buffer),
520                  length,
521                  base::MessageLoopProxy::current(),
522                  callback));
523 }
524
525 void UsbDeviceHandle::RefreshEndpointMap() {
526   DCHECK(thread_checker_.CalledOnValidThread());
527   endpoint_map_.clear();
528   for (ClaimedInterfaceMap::iterator it = claimed_interfaces_.begin();
529       it != claimed_interfaces_.end(); ++it) {
530     scoped_refptr<const UsbInterfaceAltSettingDescriptor> interface_desc =
531         interfaces_->GetInterface(it->first)->GetAltSetting(
532             it->second->alternate_setting());
533     for (size_t i = 0; i < interface_desc->GetNumEndpoints(); i++) {
534       scoped_refptr<const UsbEndpointDescriptor> endpoint =
535           interface_desc->GetEndpoint(i);
536       endpoint_map_[endpoint->GetAddress()] = it->first;
537     }
538   }
539 }
540
541 scoped_refptr<UsbDeviceHandle::InterfaceClaimer>
542     UsbDeviceHandle::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
543   unsigned char address = endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK;
544   if (ContainsKey(endpoint_map_, address))
545     return claimed_interfaces_[endpoint_map_[address]];
546   return NULL;
547 }
548
549 void UsbDeviceHandle::SubmitTransfer(
550     PlatformUsbTransferHandle handle,
551     UsbTransferType transfer_type,
552     net::IOBuffer* buffer,
553     const size_t length,
554     scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
555     const UsbTransferCallback& callback) {
556   DCHECK(thread_checker_.CalledOnValidThread());
557   if (!device_) {
558     message_loop_proxy->PostTask(
559         FROM_HERE,
560         base::Bind(callback, USB_TRANSFER_DISCONNECT,
561                    make_scoped_refptr(buffer), 0));
562   }
563
564   Transfer transfer;
565   transfer.transfer_type = transfer_type;
566   transfer.buffer = buffer;
567   transfer.length = length;
568   transfer.callback = callback;
569   transfer.message_loop_proxy = message_loop_proxy;
570
571   // It's OK for this method to return NULL. libusb_submit_transfer will fail if
572   // it requires an interface we didn't claim.
573   transfer.claimed_interface = GetClaimedInterfaceForEndpoint(handle->endpoint);
574
575   if (libusb_submit_transfer(handle) == LIBUSB_SUCCESS) {
576     transfers_[handle] = transfer;
577   } else {
578     message_loop_proxy->PostTask(
579         FROM_HERE,
580         base::Bind(callback, USB_TRANSFER_ERROR,
581                    make_scoped_refptr(buffer), 0));
582   }
583 }
584
585 void UsbDeviceHandle::InternalClose() {
586   DCHECK(thread_checker_.CalledOnValidThread());
587   if (!device_) return;
588
589   // Cancel all the transfers.
590   for (TransferMap::iterator it = transfers_.begin();
591       it != transfers_.end(); ++it) {
592     // The callback will be called some time later.
593     libusb_cancel_transfer(it->first);
594   }
595
596   // Attempt-release all the interfaces.
597   // It will be retained until the transfer cancellation is finished.
598   claimed_interfaces_.clear();
599
600   // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
601   // finish.
602   device_ = NULL;
603 }