OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "device/usb/usb_device_impl.h" | 5 #include "device/usb/usb_device_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/sequenced_task_runner.h" |
11 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
12 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/strings/utf_string_conversions.h" | |
15 #include "base/thread_task_runner_handle.h" | 14 #include "base/thread_task_runner_handle.h" |
16 #include "components/device_event_log/device_event_log.h" | 15 #include "components/device_event_log/device_event_log.h" |
17 #include "device/usb/usb_context.h" | 16 #include "device/usb/usb_context.h" |
18 #include "device/usb/usb_descriptors.h" | 17 #include "device/usb/usb_descriptors.h" |
19 #include "device/usb/usb_device_handle_impl.h" | 18 #include "device/usb/usb_device_handle_impl.h" |
20 #include "device/usb/usb_error.h" | 19 #include "device/usb/usb_error.h" |
21 #include "third_party/libusb/src/libusb/libusb.h" | 20 #include "third_party/libusb/src/libusb/libusb.h" |
22 | 21 |
23 #if defined(OS_CHROMEOS) | 22 #if defined(OS_CHROMEOS) |
24 #include "base/sys_info.h" | 23 #include "base/sys_info.h" |
25 #include "chromeos/dbus/dbus_thread_manager.h" | 24 #include "chromeos/dbus/dbus_thread_manager.h" |
26 #include "chromeos/dbus/permission_broker_client.h" | 25 #include "chromeos/dbus/permission_broker_client.h" |
27 #endif // defined(OS_CHROMEOS) | 26 #endif // defined(OS_CHROMEOS) |
28 | 27 |
29 #if defined(USE_UDEV) | |
30 #include "device/udev_linux/scoped_udev.h" | |
31 #endif // defined(USE_UDEV) | |
32 | |
33 namespace device { | 28 namespace device { |
34 | 29 |
35 namespace { | 30 namespace { |
36 | 31 |
37 #if defined(OS_CHROMEOS) | |
38 void OnRequestUsbAccessReplied( | |
39 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
40 const base::Callback<void(bool success)>& callback, | |
41 bool success) { | |
42 task_runner->PostTask(FROM_HERE, base::Bind(callback, success)); | |
43 } | |
44 #endif // defined(OS_CHROMEOS) | |
45 | |
46 UsbEndpointDirection GetDirection( | 32 UsbEndpointDirection GetDirection( |
47 const libusb_endpoint_descriptor* descriptor) { | 33 const libusb_endpoint_descriptor* descriptor) { |
48 switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) { | 34 switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) { |
49 case LIBUSB_ENDPOINT_IN: | 35 case LIBUSB_ENDPOINT_IN: |
50 return USB_DIRECTION_INBOUND; | 36 return USB_DIRECTION_INBOUND; |
51 case LIBUSB_ENDPOINT_OUT: | 37 case LIBUSB_ENDPOINT_OUT: |
52 return USB_DIRECTION_OUTBOUND; | 38 return USB_DIRECTION_OUTBOUND; |
53 default: | 39 default: |
54 NOTREACHED(); | 40 NOTREACHED(); |
55 return USB_DIRECTION_INBOUND; | 41 return USB_DIRECTION_INBOUND; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 default: | 86 default: |
101 NOTREACHED(); | 87 NOTREACHED(); |
102 return USB_USAGE_DATA; | 88 return USB_USAGE_DATA; |
103 } | 89 } |
104 } | 90 } |
105 | 91 |
106 } // namespace | 92 } // namespace |
107 | 93 |
108 UsbDeviceImpl::UsbDeviceImpl( | 94 UsbDeviceImpl::UsbDeviceImpl( |
109 scoped_refptr<UsbContext> context, | 95 scoped_refptr<UsbContext> context, |
110 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, | |
111 PlatformUsbDevice platform_device, | 96 PlatformUsbDevice platform_device, |
112 uint16 vendor_id, | 97 uint16 vendor_id, |
113 uint16 product_id, | 98 uint16 product_id, |
114 uint32 unique_id) | 99 uint32 unique_id, |
115 : UsbDevice(vendor_id, product_id, unique_id), | 100 const base::string16& manufacturer_string, |
| 101 const base::string16& product_string, |
| 102 const base::string16& serial_number, |
| 103 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) |
| 104 : UsbDevice(vendor_id, |
| 105 product_id, |
| 106 unique_id, |
| 107 manufacturer_string, |
| 108 product_string, |
| 109 serial_number), |
116 platform_device_(platform_device), | 110 platform_device_(platform_device), |
117 context_(context), | 111 context_(context), |
118 ui_task_runner_(ui_task_runner) { | 112 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 113 blocking_task_runner_(blocking_task_runner) { |
119 CHECK(platform_device) << "platform_device cannot be NULL"; | 114 CHECK(platform_device) << "platform_device cannot be NULL"; |
120 libusb_ref_device(platform_device); | 115 libusb_ref_device(platform_device); |
121 RefreshConfiguration(); | 116 RefreshConfiguration(); |
122 #if defined(USE_UDEV) | |
123 ScopedUdevPtr udev(udev_new()); | |
124 ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev.get())); | |
125 | |
126 udev_enumerate_add_match_subsystem(enumerate.get(), "usb"); | |
127 if (udev_enumerate_scan_devices(enumerate.get()) != 0) { | |
128 return; | |
129 } | |
130 std::string bus_number = | |
131 base::IntToString(libusb_get_bus_number(platform_device)); | |
132 std::string device_address = | |
133 base::IntToString(libusb_get_device_address(platform_device)); | |
134 udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get()); | |
135 for (udev_list_entry* i = devices; i != NULL; | |
136 i = udev_list_entry_get_next(i)) { | |
137 ScopedUdevDevicePtr device( | |
138 udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i))); | |
139 if (device) { | |
140 const char* value = udev_device_get_sysattr_value(device.get(), "busnum"); | |
141 if (!value || bus_number != value) { | |
142 continue; | |
143 } | |
144 value = udev_device_get_sysattr_value(device.get(), "devnum"); | |
145 if (!value || device_address != value) { | |
146 continue; | |
147 } | |
148 | |
149 #if defined(OS_CHROMEOS) | |
150 value = udev_device_get_devnode(device.get()); | |
151 if (value) { | |
152 devnode_ = value; | |
153 } | |
154 #endif | |
155 value = udev_device_get_sysattr_value(device.get(), "manufacturer"); | |
156 if (value) { | |
157 manufacturer_ = base::UTF8ToUTF16(value); | |
158 } | |
159 value = udev_device_get_sysattr_value(device.get(), "product"); | |
160 if (value) { | |
161 product_ = base::UTF8ToUTF16(value); | |
162 } | |
163 value = udev_device_get_sysattr_value(device.get(), "serial"); | |
164 if (value) { | |
165 serial_number_ = base::UTF8ToUTF16(value); | |
166 } | |
167 break; | |
168 } | |
169 } | |
170 #else | |
171 strings_cached_ = false; | |
172 #endif | |
173 } | 117 } |
174 | 118 |
175 UsbDeviceImpl::~UsbDeviceImpl() { | 119 UsbDeviceImpl::~UsbDeviceImpl() { |
176 // The destructor must be safe to call from any thread. | 120 // The destructor must be safe to call from any thread. |
177 libusb_unref_device(platform_device_); | 121 libusb_unref_device(platform_device_); |
178 } | 122 } |
179 | 123 |
180 #if defined(OS_CHROMEOS) | 124 #if defined(OS_CHROMEOS) |
181 | 125 |
182 void UsbDeviceImpl::RequestUsbAccess( | 126 void UsbDeviceImpl::RequestUsbAccess( |
183 int interface_id, | 127 int interface_id, |
184 const base::Callback<void(bool success)>& callback) { | 128 const base::Callback<void(bool success)>& callback) { |
185 DCHECK(thread_checker_.CalledOnValidThread()); | 129 DCHECK(thread_checker_.CalledOnValidThread()); |
186 | 130 |
187 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to | 131 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to |
188 // use permission broker. | 132 // use permission broker. |
189 if (base::SysInfo::IsRunningOnChromeOS()) { | 133 if (base::SysInfo::IsRunningOnChromeOS()) { |
190 chromeos::PermissionBrokerClient* client = | 134 chromeos::PermissionBrokerClient* client = |
191 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient(); | 135 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient(); |
192 DCHECK(client) << "Could not get permission broker client."; | 136 DCHECK(client) << "Could not get permission broker client."; |
193 if (!client) { | 137 if (client) { |
| 138 client->RequestPathAccess(devnode_, interface_id, callback); |
| 139 } else { |
194 callback.Run(false); | 140 callback.Run(false); |
195 return; | |
196 } | 141 } |
197 | |
198 ui_task_runner_->PostTask( | |
199 FROM_HERE, | |
200 base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess, | |
201 base::Unretained(client), | |
202 devnode_, | |
203 interface_id, | |
204 base::Bind(&OnRequestUsbAccessReplied, | |
205 base::ThreadTaskRunnerHandle::Get(), | |
206 callback))); | |
207 } else { | 142 } else { |
208 // Not really running on Chrome OS, declare success. | 143 // Not really running on Chrome OS, declare success. |
209 callback.Run(true); | 144 callback.Run(true); |
210 } | 145 } |
211 } | 146 } |
212 | 147 |
213 #endif | 148 #endif |
214 | 149 |
215 scoped_refptr<UsbDeviceHandle> UsbDeviceImpl::Open() { | 150 void UsbDeviceImpl::Open(const OpenCallback& callback) { |
216 DCHECK(thread_checker_.CalledOnValidThread()); | 151 DCHECK(thread_checker_.CalledOnValidThread()); |
217 PlatformUsbDeviceHandle handle; | 152 blocking_task_runner_->PostTask( |
218 const int rv = libusb_open(platform_device_, &handle); | 153 FROM_HERE, |
219 if (LIBUSB_SUCCESS == rv) { | 154 base::Bind(&UsbDeviceImpl::OpenOnBlockingThread, this, callback)); |
220 scoped_refptr<UsbDeviceHandleImpl> device_handle = | |
221 new UsbDeviceHandleImpl(context_, this, handle); | |
222 handles_.push_back(device_handle); | |
223 return device_handle; | |
224 } else { | |
225 USB_LOG(EVENT) << "Failed to open device: " | |
226 << ConvertPlatformUsbErrorToString(rv); | |
227 return NULL; | |
228 } | |
229 } | 155 } |
230 | 156 |
231 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) { | 157 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) { |
232 DCHECK(thread_checker_.CalledOnValidThread()); | 158 DCHECK(thread_checker_.CalledOnValidThread()); |
233 | 159 |
234 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end(); | 160 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end(); |
235 ++it) { | 161 ++it) { |
236 if (it->get() == handle.get()) { | 162 if (it->get() == handle.get()) { |
237 (*it)->InternalClose(); | 163 (*it)->InternalClose(); |
238 handles_.erase(it); | 164 handles_.erase(it); |
239 return true; | 165 return true; |
240 } | 166 } |
241 } | 167 } |
242 return false; | 168 return false; |
243 } | 169 } |
244 | 170 |
245 const UsbConfigDescriptor* UsbDeviceImpl::GetConfiguration() { | 171 const UsbConfigDescriptor* UsbDeviceImpl::GetConfiguration() { |
246 DCHECK(thread_checker_.CalledOnValidThread()); | 172 DCHECK(thread_checker_.CalledOnValidThread()); |
247 return configuration_.get(); | 173 return configuration_.get(); |
248 } | 174 } |
249 | 175 |
250 bool UsbDeviceImpl::GetManufacturer(base::string16* manufacturer) { | |
251 DCHECK(thread_checker_.CalledOnValidThread()); | |
252 | |
253 #if !defined(USE_UDEV) | |
254 if (!strings_cached_) { | |
255 CacheStrings(); | |
256 } | |
257 #endif | |
258 | |
259 *manufacturer = manufacturer_; | |
260 return !manufacturer_.empty(); | |
261 } | |
262 | |
263 bool UsbDeviceImpl::GetProduct(base::string16* product) { | |
264 DCHECK(thread_checker_.CalledOnValidThread()); | |
265 | |
266 #if !defined(USE_UDEV) | |
267 if (!strings_cached_) { | |
268 CacheStrings(); | |
269 } | |
270 #endif | |
271 | |
272 *product = product_; | |
273 return !product_.empty(); | |
274 } | |
275 | |
276 bool UsbDeviceImpl::GetSerialNumber(base::string16* serial_number) { | |
277 DCHECK(thread_checker_.CalledOnValidThread()); | |
278 | |
279 #if !defined(USE_UDEV) | |
280 if (!strings_cached_) { | |
281 CacheStrings(); | |
282 } | |
283 #endif | |
284 | |
285 *serial_number = serial_number_; | |
286 return !serial_number_.empty(); | |
287 } | |
288 | |
289 void UsbDeviceImpl::OnDisconnect() { | 176 void UsbDeviceImpl::OnDisconnect() { |
290 DCHECK(thread_checker_.CalledOnValidThread()); | 177 DCHECK(thread_checker_.CalledOnValidThread()); |
291 | 178 |
292 // Swap the list of handles into a local variable because closing all open | 179 // Swap the list of handles into a local variable because closing all open |
293 // handles may release the last reference to this object. | 180 // handles may release the last reference to this object. |
294 HandlesVector handles; | 181 HandlesVector handles; |
295 swap(handles, handles_); | 182 swap(handles, handles_); |
296 | 183 |
297 for (const scoped_refptr<UsbDeviceHandleImpl>& handle : handles_) { | 184 for (const scoped_refptr<UsbDeviceHandleImpl>& handle : handles_) { |
298 handle->InternalClose(); | 185 handle->InternalClose(); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 } | 244 } |
358 } | 245 } |
359 | 246 |
360 configuration_->extra_data = std::vector<uint8_t>( | 247 configuration_->extra_data = std::vector<uint8_t>( |
361 platform_config->extra, | 248 platform_config->extra, |
362 platform_config->extra + platform_config->extra_length); | 249 platform_config->extra + platform_config->extra_length); |
363 | 250 |
364 libusb_free_config_descriptor(platform_config); | 251 libusb_free_config_descriptor(platform_config); |
365 } | 252 } |
366 | 253 |
367 #if !defined(USE_UDEV) | 254 void UsbDeviceImpl::OpenOnBlockingThread(const OpenCallback& callback) { |
368 void UsbDeviceImpl::CacheStrings() { | 255 PlatformUsbDeviceHandle handle; |
| 256 const int rv = libusb_open(platform_device_, &handle); |
| 257 if (LIBUSB_SUCCESS == rv) { |
| 258 task_runner_->PostTask( |
| 259 FROM_HERE, base::Bind(&UsbDeviceImpl::Opened, this, handle, callback)); |
| 260 } else { |
| 261 USB_LOG(EVENT) << "Failed to open device: " |
| 262 << ConvertPlatformUsbErrorToString(rv); |
| 263 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
| 264 } |
| 265 } |
| 266 |
| 267 void UsbDeviceImpl::Opened(PlatformUsbDeviceHandle platform_handle, |
| 268 const OpenCallback& callback) { |
369 DCHECK(thread_checker_.CalledOnValidThread()); | 269 DCHECK(thread_checker_.CalledOnValidThread()); |
370 // This is a non-blocking call as libusb has the descriptor in memory. | 270 scoped_refptr<UsbDeviceHandleImpl> device_handle = new UsbDeviceHandleImpl( |
371 libusb_device_descriptor desc; | 271 context_, this, platform_handle, blocking_task_runner_); |
372 const int rv = libusb_get_device_descriptor(platform_device_, &desc); | 272 handles_.push_back(device_handle); |
373 if (rv == LIBUSB_SUCCESS) { | 273 callback.Run(device_handle); |
374 scoped_refptr<UsbDeviceHandle> device_handle = Open(); | |
375 if (device_handle.get()) { | |
376 if (desc.iManufacturer != 0) { | |
377 device_handle->GetStringDescriptor(desc.iManufacturer, &manufacturer_); | |
378 } | |
379 if (desc.iProduct != 0) { | |
380 device_handle->GetStringDescriptor(desc.iProduct, &product_); | |
381 } | |
382 if (desc.iSerialNumber != 0) { | |
383 device_handle->GetStringDescriptor(desc.iSerialNumber, &serial_number_); | |
384 } | |
385 device_handle->Close(); | |
386 } else { | |
387 USB_LOG(EVENT) << "Failed to open device to cache string descriptors."; | |
388 } | |
389 } else { | |
390 USB_LOG(EVENT) | |
391 << "Failed to read device descriptor to cache string descriptors: " | |
392 << ConvertPlatformUsbErrorToString(rv); | |
393 } | |
394 strings_cached_ = true; | |
395 } | 274 } |
396 #endif // !defined(USE_UDEV) | |
397 | 275 |
398 } // namespace device | 276 } // namespace device |
OLD | NEW |