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_impl.h" 6 7#include <algorithm> 8 9#include "base/stl_util.h" 10#include "components/usb_service/usb_context.h" 11#include "components/usb_service/usb_device_handle_impl.h" 12#include "components/usb_service/usb_error.h" 13#include "components/usb_service/usb_interface_impl.h" 14#include "content/public/browser/browser_thread.h" 15#include "third_party/libusb/src/libusb/libusb.h" 16 17#if defined(OS_CHROMEOS) 18#include "base/sys_info.h" 19#include "chromeos/dbus/dbus_thread_manager.h" 20#include "chromeos/dbus/permission_broker_client.h" 21#endif // defined(OS_CHROMEOS) 22 23using content::BrowserThread; 24 25namespace { 26 27#if defined(OS_CHROMEOS) 28void OnRequestUsbAccessReplied( 29 const base::Callback<void(bool success)>& callback, 30 bool success) { 31 BrowserThread::PostTask( 32 BrowserThread::FILE, FROM_HERE, base::Bind(callback, success)); 33} 34#endif // defined(OS_CHROMEOS) 35 36} // namespace 37 38namespace usb_service { 39 40UsbDeviceImpl::UsbDeviceImpl(scoped_refptr<UsbContext> context, 41 PlatformUsbDevice platform_device, 42 uint16 vendor_id, 43 uint16 product_id, 44 uint32 unique_id) 45 : UsbDevice(vendor_id, product_id, unique_id), 46 platform_device_(platform_device), 47 context_(context) { 48 CHECK(platform_device) << "platform_device cannot be NULL"; 49 libusb_ref_device(platform_device); 50} 51 52UsbDeviceImpl::~UsbDeviceImpl() { 53 DCHECK(thread_checker_.CalledOnValidThread()); 54 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end(); 55 ++it) { 56 (*it)->InternalClose(); 57 } 58 STLClearObject(&handles_); 59 libusb_unref_device(platform_device_); 60} 61 62#if defined(OS_CHROMEOS) 63 64void UsbDeviceImpl::RequestUsbAcess( 65 int interface_id, 66 const base::Callback<void(bool success)>& callback) { 67 DCHECK(thread_checker_.CalledOnValidThread()); 68 69 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to 70 // use permission broker. 71 if (base::SysInfo::IsRunningOnChromeOS()) { 72 chromeos::PermissionBrokerClient* client = 73 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient(); 74 DCHECK(client) << "Could not get permission broker client."; 75 if (!client) { 76 callback.Run(false); 77 return; 78 } 79 80 BrowserThread::PostTask( 81 BrowserThread::UI, 82 FROM_HERE, 83 base::Bind(&chromeos::PermissionBrokerClient::RequestUsbAccess, 84 base::Unretained(client), 85 vendor_id(), 86 product_id(), 87 interface_id, 88 base::Bind(&OnRequestUsbAccessReplied, callback))); 89 } 90} 91 92#endif 93 94scoped_refptr<UsbDeviceHandle> UsbDeviceImpl::Open() { 95 DCHECK(thread_checker_.CalledOnValidThread()); 96 PlatformUsbDeviceHandle handle; 97 const int rv = libusb_open(platform_device_, &handle); 98 if (LIBUSB_SUCCESS == rv) { 99 scoped_refptr<UsbConfigDescriptor> interfaces = ListInterfaces(); 100 if (!interfaces) 101 return NULL; 102 scoped_refptr<UsbDeviceHandleImpl> device_handle = 103 new UsbDeviceHandleImpl(context_, this, handle, interfaces); 104 handles_.push_back(device_handle); 105 return device_handle; 106 } else { 107 LOG(ERROR) << "Failed to open device: " << ConvertErrorToString(rv); 108 return NULL; 109 } 110} 111 112bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) { 113 DCHECK(thread_checker_.CalledOnValidThread()); 114 115 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end(); 116 ++it) { 117 if (*it == handle) { 118 (*it)->InternalClose(); 119 handles_.erase(it); 120 return true; 121 } 122 } 123 return false; 124} 125 126scoped_refptr<UsbConfigDescriptor> UsbDeviceImpl::ListInterfaces() { 127 DCHECK(thread_checker_.CalledOnValidThread()); 128 129 PlatformUsbConfigDescriptor platform_config; 130 const int rv = 131 libusb_get_active_config_descriptor(platform_device_, &platform_config); 132 if (rv == LIBUSB_SUCCESS) { 133 return new UsbConfigDescriptorImpl(platform_config); 134 } else { 135 LOG(ERROR) << "Failed to get config descriptor: " 136 << ConvertErrorToString(rv); 137 return NULL; 138 } 139} 140 141void UsbDeviceImpl::OnDisconnect() { 142 DCHECK(thread_checker_.CalledOnValidThread()); 143 HandlesVector handles; 144 swap(handles, handles_); 145 for (HandlesVector::iterator it = handles.begin(); it != handles.end(); ++it) 146 (*it)->InternalClose(); 147} 148 149} // namespace usb_service 150