blob: 15e6abfc1e9f090e7ab2503201661af6812cfc9d [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]d165a6442013-08-08 19:38:117#include <set>
[email protected]22ac24e2012-10-03 17:56:058#include <vector>
9
[email protected]320a7b72013-09-05 01:51:2710#include "base/basictypes.h"
[email protected]1c39a6b2012-04-27 16:09:5711#include "base/bind.h"
12#include "base/bind_helpers.h"
[email protected]88a05cf42012-05-16 21:36:2313#include "base/logging.h"
[email protected]320a7b72013-09-05 01:51:2714#include "base/memory/ref_counted.h"
[email protected]1c39a6b2012-04-27 16:09:5715#include "base/stl_util.h"
[email protected]99dcfca2013-08-05 01:28:5916#include "chrome/browser/chrome_notification_types.h"
17#include "chrome/browser/usb/usb_context.h"
[email protected]320a7b72013-09-05 01:51:2718#include "chrome/browser/usb/usb_device.h"
[email protected]57a6bfe2013-07-23 19:26:4819#include "chrome/browser/usb/usb_device_handle.h"
[email protected]99dcfca2013-08-05 01:28:5920#include "content/public/browser/browser_thread.h"
21#include "content/public/browser/notification_observer.h"
22#include "content/public/browser/notification_registrar.h"
23#include "content/public/browser/notification_service.h"
[email protected]62c76b52013-01-08 19:04:3124#include "third_party/libusb/src/libusb/libusb.h"
[email protected]1c39a6b2012-04-27 16:09:5725
[email protected]99dcfca2013-08-05 01:28:5926namespace content {
27
28class NotificationDetails;
29class NotificationSource;
30
31} // namespace content
32
33using content::BrowserThread;
[email protected]22ac24e2012-10-03 17:56:0534using std::vector;
35
[email protected]99dcfca2013-08-05 01:28:5936namespace {
37
38class ExitObserver : public content::NotificationObserver {
[email protected]88a05cf42012-05-16 21:36:2339 public:
[email protected]99dcfca2013-08-05 01:28:5940 explicit ExitObserver(UsbService* service) : service_(service) {
[email protected]f2ecf785b2013-09-05 11:17:4741 BrowserThread::PostTask(
42 BrowserThread::UI, FROM_HERE,
43 base::Bind(&content::NotificationRegistrar::Add,
44 base::Unretained(&registrar_), this,
45 chrome::NOTIFICATION_APP_TERMINATING,
46 content::NotificationService::AllSources()));
[email protected]88a05cf42012-05-16 21:36:2347 }
48
49 private:
[email protected]99dcfca2013-08-05 01:28:5950 // content::NotificationObserver
51 virtual void Observe(int type,
52 const content::NotificationSource& source,
53 const content::NotificationDetails& details) OVERRIDE {
54 if (type == chrome::NOTIFICATION_APP_TERMINATING) {
[email protected]99dcfca2013-08-05 01:28:5955 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, service_);
[email protected]f2ecf785b2013-09-05 11:17:4756 delete this;
[email protected]99dcfca2013-08-05 01:28:5957 }
58 }
59 UsbService* service_;
60 content::NotificationRegistrar registrar_;
[email protected]88a05cf42012-05-16 21:36:2361};
62
[email protected]99dcfca2013-08-05 01:28:5963} // namespace
64
[email protected]d165a6442013-08-08 19:38:1165using content::BrowserThread;
66
[email protected]5764dcce2013-09-05 20:43:3967UsbService::UsbService(PlatformUsbContext context)
68 : context_(new UsbContext(context)),
[email protected]320a7b72013-09-05 01:51:2769 next_unique_id_(0) {
[email protected]99dcfca2013-08-05 01:28:5970 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]f2ecf785b2013-09-05 11:17:4771 // Will be deleted upon NOTIFICATION_APP_TERMINATING.
72 new ExitObserver(this);
[email protected]1c39a6b2012-04-27 16:09:5773}
74
[email protected]96816d22013-07-26 11:33:1775UsbService::~UsbService() {
[email protected]99dcfca2013-08-05 01:28:5976 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]320a7b72013-09-05 01:51:2777 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
[email protected]d165a6442013-08-08 19:38:1178 it->second->OnDisconnect();
79 }
[email protected]1c39a6b2012-04-27 16:09:5780}
81
[email protected]5764dcce2013-09-05 20:43:3982struct InitUsbContextTraits : public LeakySingletonTraits<UsbService> {
83 // LeakySingletonTraits<UsbService>
84 static UsbService* New() {
85 PlatformUsbContext context = NULL;
86 if (libusb_init(&context) != LIBUSB_SUCCESS)
87 return NULL;
88 if (!context)
89 return NULL;
90 return new UsbService(context);
91 }
92};
93
[email protected]96816d22013-07-26 11:33:1794UsbService* UsbService::GetInstance() {
[email protected]99dcfca2013-08-05 01:28:5995 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
96 // UsbService deletes itself upon APP_TERMINATING.
[email protected]5764dcce2013-09-05 20:43:3997 return Singleton<UsbService, InitUsbContextTraits>::get();
[email protected]96816d22013-07-26 11:33:1798}
99
[email protected]d165a6442013-08-08 19:38:11100void UsbService::GetDevices(std::vector<scoped_refptr<UsbDevice> >* devices) {
101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
102 STLClearObject(devices);
103 RefreshDevices();
[email protected]62269732013-07-02 19:51:31104
[email protected]320a7b72013-09-05 01:51:27105 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
[email protected]d165a6442013-08-08 19:38:11106 devices->push_back(it->second);
[email protected]62269732013-07-02 19:51:31107 }
108}
109
[email protected]320a7b72013-09-05 01:51:27110scoped_refptr<UsbDevice> UsbService::GetDeviceById(uint32 unique_id) {
[email protected]d165a6442013-08-08 19:38:11111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]d165a6442013-08-08 19:38:11112 RefreshDevices();
[email protected]22ac24e2012-10-03 17:56:05113
[email protected]320a7b72013-09-05 01:51:27114 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
115 if (it->second->unique_id() == unique_id) return it->second;
[email protected]22ac24e2012-10-03 17:56:05116 }
[email protected]320a7b72013-09-05 01:51:27117 return NULL;
[email protected]22ac24e2012-10-03 17:56:05118}
119
[email protected]d165a6442013-08-08 19:38:11120void UsbService::RefreshDevices() {
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
122
123 libusb_device** platform_devices = NULL;
124 const ssize_t device_count =
125 libusb_get_device_list(context_->context(), &platform_devices);
126
127 std::set<UsbDevice*> connected_devices;
128 vector<PlatformUsbDevice> disconnected_devices;
129
130 // Populates new devices.
131 for (ssize_t i = 0; i < device_count; ++i) {
132 if (!ContainsKey(devices_, platform_devices[i])) {
133 libusb_device_descriptor descriptor;
134 // This test is needed. A valid vendor/produce pair is required.
135 if (0 != libusb_get_device_descriptor(platform_devices[i], &descriptor))
136 continue;
137 UsbDevice* new_device = new UsbDevice(context_,
[email protected]320a7b72013-09-05 01:51:27138 platform_devices[i],
139 descriptor.idVendor,
140 descriptor.idProduct,
141 ++next_unique_id_);
[email protected]d165a6442013-08-08 19:38:11142 devices_[platform_devices[i]] = new_device;
143 connected_devices.insert(new_device);
144 } else {
145 connected_devices.insert(devices_[platform_devices[i]].get());
146 }
[email protected]1c39a6b2012-04-27 16:09:57147 }
[email protected]22ac24e2012-10-03 17:56:05148
[email protected]d165a6442013-08-08 19:38:11149 // Find disconnected devices.
150 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
151 if (!ContainsKey(connected_devices, it->second)) {
152 disconnected_devices.push_back(it->first);
153 }
[email protected]22ac24e2012-10-03 17:56:05154 }
155
[email protected]d165a6442013-08-08 19:38:11156 // Remove disconnected devices from devices_.
157 for (size_t i = 0; i < disconnected_devices.size(); ++i) {
158 // UsbDevice will be destroyed after this. The corresponding
159 // PlatformUsbDevice will be unref'ed during this process.
160 devices_.erase(disconnected_devices[i]);
161 }
162
163 libusb_free_device_list(platform_devices, true);
[email protected]22ac24e2012-10-03 17:56:05164}