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