blob: e44c8aaae9dfa932383b12cbf173ba387e8b79bb [file] [log] [blame]
[email protected]1c39a6b2012-04-27 16:09:571// Copyright (c) 2012 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_service.h"
6
[email protected]22ac24e2012-10-03 17:56:057#include <vector>
8
[email protected]1c39a6b2012-04-27 16:09:579#include "base/bind.h"
10#include "base/bind_helpers.h"
[email protected]88a05cf42012-05-16 21:36:2311#include "base/logging.h"
[email protected]1c39a6b2012-04-27 16:09:5712#include "base/stl_util.h"
13#include "chrome/browser/usb/usb_device.h"
[email protected]62c76b52013-01-08 19:04:3114#include "third_party/libusb/src/libusb/libusb.h"
[email protected]1c39a6b2012-04-27 16:09:5715
[email protected]cbcdbdf2012-11-14 17:19:4316#if defined(OS_CHROMEOS)
[email protected]211a3f32013-05-28 21:48:1817#include "base/chromeos/chromeos_version.h"
[email protected]cbcdbdf2012-11-14 17:19:4318#include "chromeos/dbus/dbus_thread_manager.h"
19#include "chromeos/dbus/permission_broker_client.h"
20#endif // defined(OS_CHROMEOS)
21
[email protected]22ac24e2012-10-03 17:56:0522using std::vector;
23
[email protected]88a05cf42012-05-16 21:36:2324// The UsbEventHandler works around a design flaw in the libusb interface. There
25// is currently no way to signal to libusb that any caller into one of the event
26// handler calls should return without handling any events.
27class UsbEventHandler : public base::PlatformThread::Delegate {
28 public:
29 explicit UsbEventHandler(PlatformUsbContext context)
30 : running_(true), context_(context) {
31 base::PlatformThread::CreateNonJoinable(0, this);
32 }
33
34 virtual ~UsbEventHandler() {}
35
[email protected]b94584a2013-02-07 03:02:0836 virtual void ThreadMain() OVERRIDE {
[email protected]88a05cf42012-05-16 21:36:2337 base::PlatformThread::SetName("UsbEventHandler");
38
39 DLOG(INFO) << "UsbEventHandler started.";
40 while (running_) {
41 libusb_handle_events(context_);
42 }
43 DLOG(INFO) << "UsbEventHandler shutting down.";
44 libusb_exit(context_);
45
46 delete this;
47 }
48
49 void Stop() {
50 running_ = false;
51 }
52
53 private:
54 bool running_;
55 PlatformUsbContext context_;
56
57 DISALLOW_EVIL_CONSTRUCTORS(UsbEventHandler);
58};
59
60UsbService::UsbService() {
[email protected]1c39a6b2012-04-27 16:09:5761 libusb_init(&context_);
[email protected]88a05cf42012-05-16 21:36:2362 event_handler_ = new UsbEventHandler(context_);
[email protected]1c39a6b2012-04-27 16:09:5763}
64
65UsbService::~UsbService() {}
66
[email protected]1c39a6b2012-04-27 16:09:5767void UsbService::Cleanup() {
[email protected]88a05cf42012-05-16 21:36:2368 event_handler_->Stop();
69 event_handler_ = NULL;
[email protected]1c39a6b2012-04-27 16:09:5770}
71
[email protected]cbcdbdf2012-11-14 17:19:4372void UsbService::FindDevices(const uint16 vendor_id,
[email protected]22ac24e2012-10-03 17:56:0573 const uint16 product_id,
[email protected]8e4e5672013-06-05 07:52:1774 int interface_id,
[email protected]eb40b23d2013-02-13 22:10:5675 vector<scoped_refptr<UsbDevice> >* devices,
76 const base::Callback<void()>& callback) {
[email protected]22ac24e2012-10-03 17:56:0577 DCHECK(event_handler_) << "FindDevices called after event handler stopped.";
[email protected]cbcdbdf2012-11-14 17:19:4378#if defined(OS_CHROMEOS)
[email protected]211a3f32013-05-28 21:48:1879 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to
80 // use permission broker.
81 if (base::chromeos::IsRunningOnChromeOS()) {
82 chromeos::PermissionBrokerClient* client =
83 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
84 DCHECK(client) << "Could not get permission broker client.";
85 if (!client) {
86 callback.Run();
87 return;
88 }
[email protected]eb40b23d2013-02-13 22:10:5689
[email protected]211a3f32013-05-28 21:48:1890 client->RequestUsbAccess(vendor_id,
91 product_id,
[email protected]8e4e5672013-06-05 07:52:1792 interface_id,
[email protected]211a3f32013-05-28 21:48:1893 base::Bind(&UsbService::FindDevicesImpl,
94 base::Unretained(this),
95 vendor_id,
96 product_id,
97 devices,
98 callback));
99 } else {
100 FindDevicesImpl(vendor_id, product_id, devices, callback, true);
101 }
[email protected]cbcdbdf2012-11-14 17:19:43102#else
[email protected]eb40b23d2013-02-13 22:10:56103 FindDevicesImpl(vendor_id, product_id, devices, callback, true);
[email protected]cbcdbdf2012-11-14 17:19:43104#endif // defined(OS_CHROMEOS)
105}
106
[email protected]62269732013-07-02 19:51:31107void UsbService::EnumerateDevices(
108 std::vector<scoped_refptr<UsbDevice> >* devices) {
109 devices->clear();
110
111 DeviceVector enumerated_devices;
112 EnumerateDevicesImpl(&enumerated_devices);
113
114 for (DeviceVector::iterator it = enumerated_devices.begin();
115 it != enumerated_devices.end(); ++it) {
116 PlatformUsbDevice device = it->device();
117 UsbDevice* const wrapper = LookupOrCreateDevice(device);
118 if (wrapper)
119 devices->push_back(wrapper);
120 }
121}
122
[email protected]cbcdbdf2012-11-14 17:19:43123void UsbService::FindDevicesImpl(const uint16 vendor_id,
124 const uint16 product_id,
125 vector<scoped_refptr<UsbDevice> >* devices,
[email protected]eb40b23d2013-02-13 22:10:56126 const base::Callback<void()>& callback,
[email protected]cbcdbdf2012-11-14 17:19:43127 bool success) {
[email protected]eb40b23d2013-02-13 22:10:56128 base::ScopedClosureRunner run_callback(callback);
129
[email protected]22ac24e2012-10-03 17:56:05130 devices->clear();
131
[email protected]cbcdbdf2012-11-14 17:19:43132 // If the permission broker was unable to obtain permission for the specified
133 // devices then there is no point in attempting to enumerate the devices. On
134 // platforms without a permission broker, we assume permission is granted.
135 if (!success)
136 return;
137
[email protected]22ac24e2012-10-03 17:56:05138 DeviceVector enumerated_devices;
[email protected]62269732013-07-02 19:51:31139 EnumerateDevicesImpl(&enumerated_devices);
[email protected]22ac24e2012-10-03 17:56:05140
[email protected]62269732013-07-02 19:51:31141 for (DeviceVector::iterator it = enumerated_devices.begin();
142 it != enumerated_devices.end(); ++it) {
143 PlatformUsbDevice device = it->device();
[email protected]22ac24e2012-10-03 17:56:05144 if (DeviceMatches(device, vendor_id, product_id)) {
145 UsbDevice* const wrapper = LookupOrCreateDevice(device);
146 if (wrapper)
147 devices->push_back(wrapper);
148 }
149 }
[email protected]22ac24e2012-10-03 17:56:05150}
151
[email protected]1c39a6b2012-04-27 16:09:57152void UsbService::CloseDevice(scoped_refptr<UsbDevice> device) {
[email protected]88a05cf42012-05-16 21:36:23153 DCHECK(event_handler_) << "CloseDevice called after event handler stopped.";
[email protected]1c39a6b2012-04-27 16:09:57154
[email protected]22ac24e2012-10-03 17:56:05155 PlatformUsbDevice platform_device = libusb_get_device(device->handle());
156 if (!ContainsKey(devices_, platform_device)) {
157 LOG(WARNING) << "CloseDevice called for device we're not tracking!";
158 return;
[email protected]1c39a6b2012-04-27 16:09:57159 }
[email protected]22ac24e2012-10-03 17:56:05160
161 devices_.erase(platform_device);
162 libusb_close(device->handle());
163}
164
165UsbService::RefCountedPlatformUsbDevice::RefCountedPlatformUsbDevice(
166 PlatformUsbDevice device) : device_(device) {
167 libusb_ref_device(device_);
168}
169
170UsbService::RefCountedPlatformUsbDevice::RefCountedPlatformUsbDevice(
171 const RefCountedPlatformUsbDevice& other) : device_(other.device_) {
172 libusb_ref_device(device_);
173}
174
175UsbService::RefCountedPlatformUsbDevice::~RefCountedPlatformUsbDevice() {
176 libusb_unref_device(device_);
177}
178
179PlatformUsbDevice UsbService::RefCountedPlatformUsbDevice::device() {
180 return device_;
181}
182
[email protected]62269732013-07-02 19:51:31183void UsbService::EnumerateDevicesImpl(DeviceVector* output) {
[email protected]22ac24e2012-10-03 17:56:05184 STLClearObject(output);
185
186 libusb_device** devices = NULL;
187 const ssize_t device_count = libusb_get_device_list(context_, &devices);
188 if (device_count < 0)
189 return;
190
191 for (int i = 0; i < device_count; ++i) {
192 libusb_device* device = devices[i];
193 libusb_ref_device(device);
194 output->push_back(RefCountedPlatformUsbDevice(device));
195 }
196
197 libusb_free_device_list(devices, true);
198}
199
200bool UsbService::DeviceMatches(PlatformUsbDevice device,
201 const uint16 vendor_id,
202 const uint16 product_id) {
203 libusb_device_descriptor descriptor;
204 if (libusb_get_device_descriptor(device, &descriptor))
205 return false;
206 return descriptor.idVendor == vendor_id && descriptor.idProduct == product_id;
207}
208
209UsbDevice* UsbService::LookupOrCreateDevice(PlatformUsbDevice device) {
210 if (!ContainsKey(devices_, device)) {
211 libusb_device_handle* handle = NULL;
212 if (libusb_open(device, &handle)) {
213 LOG(WARNING) << "Could not open device.";
214 return NULL;
215 }
216
217 UsbDevice* wrapper = new UsbDevice(this, handle);
218 devices_[device] = wrapper;
219 }
[email protected]39790b7f2013-06-03 00:10:59220 return devices_[device].get();
[email protected]1c39a6b2012-04-27 16:09:57221}