OLD | NEW |
| (Empty) |
1 // 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/extensions/api/usb/usb_api.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/message_loop/message_loop_proxy.h" | |
12 #include "chrome/browser/extensions/api/usb/usb_device_resource.h" | |
13 #include "chrome/common/extensions/api/usb.h" | |
14 #include "components/usb_service/usb_device_handle.h" | |
15 #include "components/usb_service/usb_service.h" | |
16 #include "extensions/browser/extension_system.h" | |
17 #include "extensions/common/permissions/permissions_data.h" | |
18 #include "extensions/common/permissions/usb_device_permission.h" | |
19 | |
20 namespace usb = extensions::api::usb; | |
21 namespace BulkTransfer = usb::BulkTransfer; | |
22 namespace ClaimInterface = usb::ClaimInterface; | |
23 namespace CloseDevice = usb::CloseDevice; | |
24 namespace ControlTransfer = usb::ControlTransfer; | |
25 namespace FindDevices = usb::FindDevices; | |
26 namespace GetDevices = usb::GetDevices; | |
27 namespace InterruptTransfer = usb::InterruptTransfer; | |
28 namespace IsochronousTransfer = usb::IsochronousTransfer; | |
29 namespace ListInterfaces = usb::ListInterfaces; | |
30 namespace OpenDevice = usb::OpenDevice; | |
31 namespace ReleaseInterface = usb::ReleaseInterface; | |
32 namespace RequestAccess = usb::RequestAccess; | |
33 namespace ResetDevice = usb::ResetDevice; | |
34 namespace SetInterfaceAlternateSetting = usb::SetInterfaceAlternateSetting; | |
35 | |
36 using content::BrowserThread; | |
37 using std::string; | |
38 using std::vector; | |
39 using usb::ControlTransferInfo; | |
40 using usb::ConnectionHandle; | |
41 using usb::Device; | |
42 using usb::Direction; | |
43 using usb::EndpointDescriptor; | |
44 using usb::GenericTransferInfo; | |
45 using usb::InterfaceDescriptor; | |
46 using usb::IsochronousTransferInfo; | |
47 using usb::Recipient; | |
48 using usb::RequestType; | |
49 using usb::SynchronizationType; | |
50 using usb::TransferType; | |
51 using usb::UsageType; | |
52 using usb_service::UsbConfigDescriptor; | |
53 using usb_service::UsbDevice; | |
54 using usb_service::UsbDeviceHandle; | |
55 using usb_service::UsbEndpointDescriptor; | |
56 using usb_service::UsbEndpointDirection; | |
57 using usb_service::UsbInterfaceAltSettingDescriptor; | |
58 using usb_service::UsbInterfaceDescriptor; | |
59 using usb_service::UsbService; | |
60 using usb_service::UsbSynchronizationType; | |
61 using usb_service::UsbTransferStatus; | |
62 using usb_service::UsbTransferType; | |
63 using usb_service::UsbUsageType; | |
64 | |
65 typedef std::vector<scoped_refptr<UsbDevice> > DeviceVector; | |
66 typedef scoped_ptr<DeviceVector> ScopedDeviceVector; | |
67 | |
68 namespace { | |
69 | |
70 const char kDataKey[] = "data"; | |
71 const char kResultCodeKey[] = "resultCode"; | |
72 | |
73 const char kErrorInitService[] = "Failed to initialize USB service."; | |
74 | |
75 const char kErrorOpen[] = "Failed to open device."; | |
76 const char kErrorCancelled[] = "Transfer was cancelled."; | |
77 const char kErrorDisconnect[] = "Device disconnected."; | |
78 const char kErrorGeneric[] = "Transfer failed."; | |
79 #if !defined(OS_CHROMEOS) | |
80 const char kErrorNotSupported[] = "Not supported on this platform."; | |
81 #endif | |
82 const char kErrorOverflow[] = "Inbound transfer overflow."; | |
83 const char kErrorStalled[] = "Transfer stalled."; | |
84 const char kErrorTimeout[] = "Transfer timed out."; | |
85 const char kErrorTransferLength[] = "Transfer length is insufficient."; | |
86 | |
87 const char kErrorCannotListInterfaces[] = "Error listing interfaces."; | |
88 const char kErrorCannotClaimInterface[] = "Error claiming interface."; | |
89 const char kErrorCannotReleaseInterface[] = "Error releasing interface."; | |
90 const char kErrorCannotSetInterfaceAlternateSetting[] = | |
91 "Error setting alternate interface setting."; | |
92 const char kErrorConvertDirection[] = "Invalid transfer direction."; | |
93 const char kErrorConvertRecipient[] = "Invalid transfer recipient."; | |
94 const char kErrorConvertRequestType[] = "Invalid request type."; | |
95 const char kErrorConvertSynchronizationType[] = "Invalid synchronization type"; | |
96 const char kErrorConvertTransferType[] = "Invalid endpoint type."; | |
97 const char kErrorConvertUsageType[] = "Invalid usage type."; | |
98 const char kErrorMalformedParameters[] = "Error parsing parameters."; | |
99 const char kErrorNoDevice[] = "No such device."; | |
100 const char kErrorPermissionDenied[] = | |
101 "Permission to access device was denied"; | |
102 const char kErrorInvalidTransferLength[] = | |
103 "Transfer length must be a positive number less than 104,857,600."; | |
104 const char kErrorInvalidNumberOfPackets[] = | |
105 "Number of packets must be a positive number less than 4,194,304."; | |
106 const char kErrorInvalidPacketLength[] = "Packet length must be a " | |
107 "positive number less than 65,536."; | |
108 const char kErrorResetDevice[] = | |
109 "Error resetting the device. The device has been closed."; | |
110 | |
111 const size_t kMaxTransferLength = 100 * 1024 * 1024; | |
112 const int kMaxPackets = 4 * 1024 * 1024; | |
113 const int kMaxPacketLength = 64 * 1024; | |
114 | |
115 bool ConvertDirectionToApi(const UsbEndpointDirection& input, | |
116 Direction* output) { | |
117 switch (input) { | |
118 case usb_service::USB_DIRECTION_INBOUND: | |
119 *output = usb::DIRECTION_IN; | |
120 return true; | |
121 case usb_service::USB_DIRECTION_OUTBOUND: | |
122 *output = usb::DIRECTION_OUT; | |
123 return true; | |
124 default: | |
125 NOTREACHED(); | |
126 return false; | |
127 } | |
128 } | |
129 | |
130 bool ConvertSynchronizationTypeToApi(const UsbSynchronizationType& input, | |
131 usb::SynchronizationType* output) { | |
132 switch (input) { | |
133 case usb_service::USB_SYNCHRONIZATION_NONE: | |
134 *output = usb::SYNCHRONIZATION_TYPE_NONE; | |
135 return true; | |
136 case usb_service::USB_SYNCHRONIZATION_ASYNCHRONOUS: | |
137 *output = usb::SYNCHRONIZATION_TYPE_ASYNCHRONOUS; | |
138 return true; | |
139 case usb_service::USB_SYNCHRONIZATION_ADAPTIVE: | |
140 *output = usb::SYNCHRONIZATION_TYPE_ADAPTIVE; | |
141 return true; | |
142 case usb_service::USB_SYNCHRONIZATION_SYNCHRONOUS: | |
143 *output = usb::SYNCHRONIZATION_TYPE_SYNCHRONOUS; | |
144 return true; | |
145 default: | |
146 NOTREACHED(); | |
147 return false; | |
148 } | |
149 } | |
150 | |
151 bool ConvertTransferTypeToApi( | |
152 const UsbTransferType& input, | |
153 usb::TransferType* output) { | |
154 switch (input) { | |
155 case usb_service::USB_TRANSFER_CONTROL: | |
156 *output = usb::TRANSFER_TYPE_CONTROL; | |
157 return true; | |
158 case usb_service::USB_TRANSFER_INTERRUPT: | |
159 *output = usb::TRANSFER_TYPE_INTERRUPT; | |
160 return true; | |
161 case usb_service::USB_TRANSFER_ISOCHRONOUS: | |
162 *output = usb::TRANSFER_TYPE_ISOCHRONOUS; | |
163 return true; | |
164 case usb_service::USB_TRANSFER_BULK: | |
165 *output = usb::TRANSFER_TYPE_BULK; | |
166 return true; | |
167 default: | |
168 NOTREACHED(); | |
169 return false; | |
170 } | |
171 } | |
172 | |
173 bool ConvertUsageTypeToApi(const UsbUsageType& input, usb::UsageType* output) { | |
174 switch (input) { | |
175 case usb_service::USB_USAGE_DATA: | |
176 *output = usb::USAGE_TYPE_DATA; | |
177 return true; | |
178 case usb_service::USB_USAGE_FEEDBACK: | |
179 *output = usb::USAGE_TYPE_FEEDBACK; | |
180 return true; | |
181 case usb_service::USB_USAGE_EXPLICIT_FEEDBACK: | |
182 *output = usb::USAGE_TYPE_EXPLICITFEEDBACK; | |
183 return true; | |
184 default: | |
185 NOTREACHED(); | |
186 return false; | |
187 } | |
188 } | |
189 | |
190 bool ConvertDirection(const Direction& input, | |
191 UsbEndpointDirection* output) { | |
192 switch (input) { | |
193 case usb::DIRECTION_IN: | |
194 *output = usb_service::USB_DIRECTION_INBOUND; | |
195 return true; | |
196 case usb::DIRECTION_OUT: | |
197 *output = usb_service::USB_DIRECTION_OUTBOUND; | |
198 return true; | |
199 default: | |
200 NOTREACHED(); | |
201 return false; | |
202 } | |
203 } | |
204 | |
205 bool ConvertRequestType(const RequestType& input, | |
206 UsbDeviceHandle::TransferRequestType* output) { | |
207 switch (input) { | |
208 case usb::REQUEST_TYPE_STANDARD: | |
209 *output = UsbDeviceHandle::STANDARD; | |
210 return true; | |
211 case usb::REQUEST_TYPE_CLASS: | |
212 *output = UsbDeviceHandle::CLASS; | |
213 return true; | |
214 case usb::REQUEST_TYPE_VENDOR: | |
215 *output = UsbDeviceHandle::VENDOR; | |
216 return true; | |
217 case usb::REQUEST_TYPE_RESERVED: | |
218 *output = UsbDeviceHandle::RESERVED; | |
219 return true; | |
220 default: | |
221 NOTREACHED(); | |
222 return false; | |
223 } | |
224 } | |
225 | |
226 bool ConvertRecipient(const Recipient& input, | |
227 UsbDeviceHandle::TransferRecipient* output) { | |
228 switch (input) { | |
229 case usb::RECIPIENT_DEVICE: | |
230 *output = UsbDeviceHandle::DEVICE; | |
231 return true; | |
232 case usb::RECIPIENT_INTERFACE: | |
233 *output = UsbDeviceHandle::INTERFACE; | |
234 return true; | |
235 case usb::RECIPIENT_ENDPOINT: | |
236 *output = UsbDeviceHandle::ENDPOINT; | |
237 return true; | |
238 case usb::RECIPIENT_OTHER: | |
239 *output = UsbDeviceHandle::OTHER; | |
240 return true; | |
241 default: | |
242 NOTREACHED(); | |
243 return false; | |
244 } | |
245 } | |
246 | |
247 template<class T> | |
248 bool GetTransferSize(const T& input, size_t* output) { | |
249 if (input.direction == usb::DIRECTION_IN) { | |
250 const int* length = input.length.get(); | |
251 if (length && *length >= 0 && | |
252 static_cast<size_t>(*length) < kMaxTransferLength) { | |
253 *output = *length; | |
254 return true; | |
255 } | |
256 } else if (input.direction == usb::DIRECTION_OUT) { | |
257 if (input.data.get()) { | |
258 *output = input.data->size(); | |
259 return true; | |
260 } | |
261 } | |
262 return false; | |
263 } | |
264 | |
265 template<class T> | |
266 scoped_refptr<net::IOBuffer> CreateBufferForTransfer( | |
267 const T& input, UsbEndpointDirection direction, size_t size) { | |
268 | |
269 if (size >= kMaxTransferLength) | |
270 return NULL; | |
271 | |
272 // Allocate a |size|-bytes buffer, or a one-byte buffer if |size| is 0. This | |
273 // is due to an impedance mismatch between IOBuffer and URBs. An IOBuffer | |
274 // cannot represent a zero-length buffer, while an URB can. | |
275 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(std::max( | |
276 static_cast<size_t>(1), size)); | |
277 | |
278 if (direction == usb_service::USB_DIRECTION_INBOUND) { | |
279 return buffer; | |
280 } else if (direction == usb_service::USB_DIRECTION_OUTBOUND) { | |
281 if (input.data.get() && size <= input.data->size()) { | |
282 memcpy(buffer->data(), input.data->data(), size); | |
283 return buffer; | |
284 } | |
285 } | |
286 NOTREACHED(); | |
287 return NULL; | |
288 } | |
289 | |
290 const char* ConvertTransferStatusToErrorString(const UsbTransferStatus status) { | |
291 switch (status) { | |
292 case usb_service::USB_TRANSFER_COMPLETED: | |
293 return ""; | |
294 case usb_service::USB_TRANSFER_ERROR: | |
295 return kErrorGeneric; | |
296 case usb_service::USB_TRANSFER_TIMEOUT: | |
297 return kErrorTimeout; | |
298 case usb_service::USB_TRANSFER_CANCELLED: | |
299 return kErrorCancelled; | |
300 case usb_service::USB_TRANSFER_STALLED: | |
301 return kErrorStalled; | |
302 case usb_service::USB_TRANSFER_DISCONNECT: | |
303 return kErrorDisconnect; | |
304 case usb_service::USB_TRANSFER_OVERFLOW: | |
305 return kErrorOverflow; | |
306 case usb_service::USB_TRANSFER_LENGTH_SHORT: | |
307 return kErrorTransferLength; | |
308 default: | |
309 NOTREACHED(); | |
310 return ""; | |
311 } | |
312 } | |
313 | |
314 #if defined(OS_CHROMEOS) | |
315 void RequestUsbDevicesAccessHelper( | |
316 ScopedDeviceVector devices, | |
317 std::vector<scoped_refptr<UsbDevice> >::iterator i, | |
318 int interface_id, | |
319 const base::Callback<void(ScopedDeviceVector result)>& callback, | |
320 bool success) { | |
321 if (success) { | |
322 ++i; | |
323 } else { | |
324 i = devices->erase(i); | |
325 } | |
326 if (i == devices->end()) { | |
327 callback.Run(devices.Pass()); | |
328 return; | |
329 } | |
330 (*i)->RequestUsbAcess(interface_id, base::Bind(RequestUsbDevicesAccessHelper, | |
331 base::Passed(devices.Pass()), | |
332 i, interface_id, callback)); | |
333 } | |
334 | |
335 void RequestUsbDevicesAccess( | |
336 ScopedDeviceVector devices, | |
337 int interface_id, | |
338 const base::Callback<void(ScopedDeviceVector result)>& callback) { | |
339 if (devices->empty()) { | |
340 callback.Run(devices.Pass()); | |
341 return; | |
342 } | |
343 std::vector<scoped_refptr<UsbDevice> >::iterator i = devices->begin(); | |
344 (*i)->RequestUsbAcess( | |
345 interface_id, | |
346 base::Bind(RequestUsbDevicesAccessHelper, base::Passed(devices.Pass()), | |
347 i, interface_id, callback)); | |
348 } | |
349 #endif // OS_CHROMEOS | |
350 | |
351 base::DictionaryValue* CreateTransferInfo( | |
352 UsbTransferStatus status, | |
353 scoped_refptr<net::IOBuffer> data, | |
354 size_t length) { | |
355 base::DictionaryValue* result = new base::DictionaryValue(); | |
356 result->SetInteger(kResultCodeKey, status); | |
357 result->Set(kDataKey, base::BinaryValue::CreateWithCopiedBuffer(data->data(), | |
358 length)); | |
359 return result; | |
360 } | |
361 | |
362 base::Value* PopulateConnectionHandle(int handle, int vendor_id, | |
363 int product_id) { | |
364 ConnectionHandle result; | |
365 result.handle = handle; | |
366 result.vendor_id = vendor_id; | |
367 result.product_id = product_id; | |
368 return result.ToValue().release(); | |
369 } | |
370 | |
371 base::Value* PopulateDevice(UsbDevice* device) { | |
372 Device result; | |
373 result.device = device->unique_id(); | |
374 result.vendor_id = device->vendor_id(); | |
375 result.product_id = device->product_id(); | |
376 return result.ToValue().release(); | |
377 } | |
378 | |
379 base::Value* PopulateInterfaceDescriptor( | |
380 int interface_number, | |
381 int alternate_setting, | |
382 int interface_class, | |
383 int interface_subclass, | |
384 int interface_protocol, | |
385 std::vector<linked_ptr<EndpointDescriptor> >* endpoints) { | |
386 InterfaceDescriptor descriptor; | |
387 descriptor.interface_number = interface_number; | |
388 descriptor.alternate_setting = alternate_setting; | |
389 descriptor.interface_class = interface_class; | |
390 descriptor.interface_subclass = interface_subclass; | |
391 descriptor.interface_protocol = interface_protocol; | |
392 descriptor.endpoints = *endpoints; | |
393 return descriptor.ToValue().release(); | |
394 } | |
395 | |
396 } // namespace | |
397 | |
398 namespace extensions { | |
399 | |
400 UsbAsyncApiFunction::UsbAsyncApiFunction() | |
401 : manager_(NULL) { | |
402 } | |
403 | |
404 UsbAsyncApiFunction::~UsbAsyncApiFunction() { | |
405 } | |
406 | |
407 bool UsbAsyncApiFunction::PrePrepare() { | |
408 manager_ = ApiResourceManager<UsbDeviceResource>::Get(browser_context()); | |
409 set_work_thread_id(BrowserThread::FILE); | |
410 return manager_ != NULL; | |
411 } | |
412 | |
413 bool UsbAsyncApiFunction::Respond() { | |
414 return error_.empty(); | |
415 } | |
416 | |
417 scoped_refptr<UsbDevice> | |
418 UsbAsyncApiFunction::GetDeviceOrOrCompleteWithError( | |
419 const Device& input_device) { | |
420 const uint16_t vendor_id = input_device.vendor_id; | |
421 const uint16_t product_id = input_device.product_id; | |
422 UsbDevicePermission::CheckParam param( | |
423 vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE); | |
424 if (!PermissionsData::CheckAPIPermissionWithParam( | |
425 GetExtension(), APIPermission::kUsbDevice, ¶m)) { | |
426 LOG(WARNING) << "Insufficient permissions to access device."; | |
427 CompleteWithError(kErrorPermissionDenied); | |
428 return NULL; | |
429 } | |
430 | |
431 UsbService* service = UsbService::GetInstance(); | |
432 if (!service) { | |
433 CompleteWithError(kErrorInitService); | |
434 return NULL; | |
435 } | |
436 scoped_refptr<UsbDevice> device; | |
437 | |
438 device = service->GetDeviceById(input_device.device); | |
439 | |
440 if (!device) { | |
441 CompleteWithError(kErrorNoDevice); | |
442 return NULL; | |
443 } | |
444 | |
445 if (device->vendor_id() != input_device.vendor_id || | |
446 device->product_id() != input_device.product_id) { | |
447 // Must act as if there is no such a device. | |
448 // Otherwise can be used to finger print unauthorized devices. | |
449 CompleteWithError(kErrorNoDevice); | |
450 return NULL; | |
451 } | |
452 | |
453 return device; | |
454 } | |
455 | |
456 scoped_refptr<UsbDeviceHandle> | |
457 UsbAsyncApiFunction::GetDeviceHandleOrCompleteWithError( | |
458 const ConnectionHandle& input_device_handle) { | |
459 UsbDeviceResource* resource = | |
460 manager_->Get(extension_->id(), input_device_handle.handle); | |
461 if (!resource) { | |
462 CompleteWithError(kErrorNoDevice); | |
463 return NULL; | |
464 } | |
465 | |
466 if (!resource->device() || !resource->device()->device()) { | |
467 CompleteWithError(kErrorDisconnect); | |
468 manager_->Remove(extension_->id(), input_device_handle.handle); | |
469 return NULL; | |
470 } | |
471 | |
472 if (resource->device()->device()->vendor_id() != | |
473 input_device_handle.vendor_id || | |
474 resource->device()->device()->product_id() != | |
475 input_device_handle.product_id) { | |
476 CompleteWithError(kErrorNoDevice); | |
477 return NULL; | |
478 } | |
479 | |
480 return resource->device(); | |
481 } | |
482 | |
483 void UsbAsyncApiFunction::RemoveUsbDeviceResource(int api_resource_id) { | |
484 manager_->Remove(extension_->id(), api_resource_id); | |
485 } | |
486 | |
487 void UsbAsyncApiFunction::CompleteWithError(const std::string& error) { | |
488 SetError(error); | |
489 AsyncWorkCompleted(); | |
490 } | |
491 | |
492 UsbAsyncApiTransferFunction::UsbAsyncApiTransferFunction() {} | |
493 | |
494 UsbAsyncApiTransferFunction::~UsbAsyncApiTransferFunction() {} | |
495 | |
496 void UsbAsyncApiTransferFunction::OnCompleted(UsbTransferStatus status, | |
497 scoped_refptr<net::IOBuffer> data, | |
498 size_t length) { | |
499 if (status != usb_service::USB_TRANSFER_COMPLETED) | |
500 SetError(ConvertTransferStatusToErrorString(status)); | |
501 | |
502 SetResult(CreateTransferInfo(status, data, length)); | |
503 AsyncWorkCompleted(); | |
504 } | |
505 | |
506 bool UsbAsyncApiTransferFunction::ConvertDirectionSafely( | |
507 const Direction& input, UsbEndpointDirection* output) { | |
508 const bool converted = ConvertDirection(input, output); | |
509 if (!converted) | |
510 SetError(kErrorConvertDirection); | |
511 return converted; | |
512 } | |
513 | |
514 bool UsbAsyncApiTransferFunction::ConvertRequestTypeSafely( | |
515 const RequestType& input, UsbDeviceHandle::TransferRequestType* output) { | |
516 const bool converted = ConvertRequestType(input, output); | |
517 if (!converted) | |
518 SetError(kErrorConvertRequestType); | |
519 return converted; | |
520 } | |
521 | |
522 bool UsbAsyncApiTransferFunction::ConvertRecipientSafely( | |
523 const Recipient& input, UsbDeviceHandle::TransferRecipient* output) { | |
524 const bool converted = ConvertRecipient(input, output); | |
525 if (!converted) | |
526 SetError(kErrorConvertRecipient); | |
527 return converted; | |
528 } | |
529 | |
530 UsbFindDevicesFunction::UsbFindDevicesFunction() {} | |
531 | |
532 UsbFindDevicesFunction::~UsbFindDevicesFunction() {} | |
533 | |
534 bool UsbFindDevicesFunction::Prepare() { | |
535 parameters_ = FindDevices::Params::Create(*args_); | |
536 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
537 return true; | |
538 } | |
539 | |
540 void UsbFindDevicesFunction::AsyncWorkStart() { | |
541 scoped_ptr<base::ListValue> result(new base::ListValue()); | |
542 | |
543 const uint16_t vendor_id = parameters_->options.vendor_id; | |
544 const uint16_t product_id = parameters_->options.product_id; | |
545 int interface_id = parameters_->options.interface_id.get() ? | |
546 *parameters_->options.interface_id.get() : | |
547 UsbDevicePermissionData::ANY_INTERFACE; | |
548 UsbDevicePermission::CheckParam param(vendor_id, product_id, interface_id); | |
549 if (!PermissionsData::CheckAPIPermissionWithParam( | |
550 GetExtension(), APIPermission::kUsbDevice, ¶m)) { | |
551 LOG(WARNING) << "Insufficient permissions to access device."; | |
552 CompleteWithError(kErrorPermissionDenied); | |
553 return; | |
554 } | |
555 | |
556 UsbService *service = UsbService::GetInstance(); | |
557 if (!service) { | |
558 CompleteWithError(kErrorInitService); | |
559 return; | |
560 } | |
561 | |
562 ScopedDeviceVector devices(new DeviceVector()); | |
563 service->GetDevices(devices.get()); | |
564 | |
565 for (DeviceVector::iterator it = devices->begin(); | |
566 it != devices->end();) { | |
567 if ((*it)->vendor_id() != vendor_id || (*it)->product_id() != product_id) { | |
568 it = devices->erase(it); | |
569 } else { | |
570 ++it; | |
571 } | |
572 } | |
573 | |
574 #if defined(OS_CHROMEOS) | |
575 RequestUsbDevicesAccess( | |
576 devices.Pass(), interface_id, | |
577 base::Bind(&UsbFindDevicesFunction::OpenDevices, this)); | |
578 #else | |
579 OpenDevices(devices.Pass()); | |
580 #endif // OS_CHROMEOS | |
581 } | |
582 | |
583 void UsbFindDevicesFunction::OpenDevices(ScopedDeviceVector devices) { | |
584 base::ListValue* result = new base::ListValue(); | |
585 | |
586 for (size_t i = 0; i < devices->size(); ++i) { | |
587 scoped_refptr<UsbDeviceHandle> device_handle = | |
588 devices->at(i)->Open(); | |
589 if (device_handle) | |
590 device_handles_.push_back(device_handle); | |
591 } | |
592 | |
593 for (size_t i = 0; i < device_handles_.size(); ++i) { | |
594 UsbDeviceHandle* const device_handle = device_handles_[i].get(); | |
595 UsbDeviceResource* const resource = | |
596 new UsbDeviceResource(extension_->id(), device_handle); | |
597 | |
598 result->Append(PopulateConnectionHandle(manager_->Add(resource), | |
599 parameters_->options.vendor_id, | |
600 parameters_->options.product_id)); | |
601 } | |
602 | |
603 SetResult(result); | |
604 AsyncWorkCompleted(); | |
605 } | |
606 | |
607 UsbGetDevicesFunction::UsbGetDevicesFunction() { | |
608 } | |
609 | |
610 UsbGetDevicesFunction::~UsbGetDevicesFunction() { | |
611 } | |
612 | |
613 bool UsbGetDevicesFunction::Prepare() { | |
614 parameters_ = GetDevices::Params::Create(*args_); | |
615 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
616 return true; | |
617 } | |
618 | |
619 void UsbGetDevicesFunction::AsyncWorkStart() { | |
620 scoped_ptr<base::ListValue> result(new base::ListValue()); | |
621 | |
622 const uint16_t vendor_id = parameters_->options.vendor_id; | |
623 const uint16_t product_id = parameters_->options.product_id; | |
624 UsbDevicePermission::CheckParam param( | |
625 vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE); | |
626 if (!PermissionsData::CheckAPIPermissionWithParam( | |
627 GetExtension(), APIPermission::kUsbDevice, ¶m)) { | |
628 LOG(WARNING) << "Insufficient permissions to access device."; | |
629 CompleteWithError(kErrorPermissionDenied); | |
630 return; | |
631 } | |
632 | |
633 UsbService* service = UsbService::GetInstance(); | |
634 if (!service) { | |
635 CompleteWithError(kErrorInitService); | |
636 return; | |
637 } | |
638 | |
639 DeviceVector devices; | |
640 service->GetDevices(&devices); | |
641 | |
642 for (DeviceVector::iterator it = devices.begin(); it != devices.end();) { | |
643 if ((*it)->vendor_id() != vendor_id || (*it)->product_id() != product_id) { | |
644 it = devices.erase(it); | |
645 } else { | |
646 ++it; | |
647 } | |
648 } | |
649 | |
650 for (size_t i = 0; i < devices.size(); ++i) { | |
651 result->Append(PopulateDevice(devices[i].get())); | |
652 } | |
653 | |
654 SetResult(result.release()); | |
655 AsyncWorkCompleted(); | |
656 } | |
657 | |
658 UsbRequestAccessFunction::UsbRequestAccessFunction() {} | |
659 | |
660 UsbRequestAccessFunction::~UsbRequestAccessFunction() {} | |
661 | |
662 bool UsbRequestAccessFunction::Prepare() { | |
663 parameters_ = RequestAccess::Params::Create(*args_); | |
664 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
665 return true; | |
666 } | |
667 | |
668 void UsbRequestAccessFunction::AsyncWorkStart() { | |
669 #if defined(OS_CHROMEOS) | |
670 scoped_refptr<UsbDevice> device = | |
671 GetDeviceOrOrCompleteWithError(parameters_->device); | |
672 if (!device) return; | |
673 | |
674 device->RequestUsbAcess(parameters_->interface_id, | |
675 base::Bind(&UsbRequestAccessFunction::OnCompleted, | |
676 this)); | |
677 #else | |
678 SetResult(new base::FundamentalValue(false)); | |
679 CompleteWithError(kErrorNotSupported); | |
680 #endif // OS_CHROMEOS | |
681 } | |
682 | |
683 void UsbRequestAccessFunction::OnCompleted(bool success) { | |
684 SetResult(new base::FundamentalValue(success)); | |
685 AsyncWorkCompleted(); | |
686 } | |
687 | |
688 UsbOpenDeviceFunction::UsbOpenDeviceFunction() {} | |
689 | |
690 UsbOpenDeviceFunction::~UsbOpenDeviceFunction() {} | |
691 | |
692 bool UsbOpenDeviceFunction::Prepare() { | |
693 parameters_ = OpenDevice::Params::Create(*args_); | |
694 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
695 return true; | |
696 } | |
697 | |
698 void UsbOpenDeviceFunction::AsyncWorkStart() { | |
699 scoped_refptr<UsbDevice> device = | |
700 GetDeviceOrOrCompleteWithError(parameters_->device); | |
701 if (!device) return; | |
702 | |
703 handle_ = device->Open(); | |
704 if (!handle_) { | |
705 SetError(kErrorOpen); | |
706 AsyncWorkCompleted(); | |
707 return; | |
708 } | |
709 | |
710 SetResult(PopulateConnectionHandle( | |
711 manager_->Add(new UsbDeviceResource(extension_->id(), handle_)), | |
712 handle_->device()->vendor_id(), | |
713 handle_->device()->product_id())); | |
714 AsyncWorkCompleted(); | |
715 } | |
716 | |
717 UsbListInterfacesFunction::UsbListInterfacesFunction() {} | |
718 | |
719 UsbListInterfacesFunction::~UsbListInterfacesFunction() {} | |
720 | |
721 bool UsbListInterfacesFunction::Prepare() { | |
722 parameters_ = ListInterfaces::Params::Create(*args_); | |
723 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
724 return true; | |
725 } | |
726 | |
727 void UsbListInterfacesFunction::AsyncWorkStart() { | |
728 scoped_refptr<UsbDeviceHandle> device_handle = | |
729 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
730 if (!device_handle) return; | |
731 | |
732 scoped_refptr<UsbConfigDescriptor> config = | |
733 device_handle->device()->ListInterfaces(); | |
734 | |
735 if (!config) { | |
736 SetError(kErrorCannotListInterfaces); | |
737 AsyncWorkCompleted(); | |
738 return; | |
739 } | |
740 | |
741 result_.reset(new base::ListValue()); | |
742 | |
743 for (size_t i = 0, num_interfaces = config->GetNumInterfaces(); | |
744 i < num_interfaces; ++i) { | |
745 scoped_refptr<const UsbInterfaceDescriptor> | |
746 usb_interface(config->GetInterface(i)); | |
747 for (size_t j = 0, num_descriptors = usb_interface->GetNumAltSettings(); | |
748 j < num_descriptors; ++j) { | |
749 scoped_refptr<const UsbInterfaceAltSettingDescriptor> descriptor | |
750 = usb_interface->GetAltSetting(j); | |
751 std::vector<linked_ptr<EndpointDescriptor> > endpoints; | |
752 for (size_t k = 0, num_endpoints = descriptor->GetNumEndpoints(); | |
753 k < num_endpoints; k++) { | |
754 scoped_refptr<const UsbEndpointDescriptor> endpoint | |
755 = descriptor->GetEndpoint(k); | |
756 linked_ptr<EndpointDescriptor> endpoint_desc(new EndpointDescriptor()); | |
757 | |
758 TransferType type; | |
759 Direction direction; | |
760 SynchronizationType synchronization; | |
761 UsageType usage; | |
762 | |
763 if (!ConvertTransferTypeSafely(endpoint->GetTransferType(), &type) || | |
764 !ConvertDirectionSafely(endpoint->GetDirection(), &direction) || | |
765 !ConvertSynchronizationTypeSafely( | |
766 endpoint->GetSynchronizationType(), &synchronization) || | |
767 !ConvertUsageTypeSafely(endpoint->GetUsageType(), &usage)) { | |
768 SetError(kErrorCannotListInterfaces); | |
769 AsyncWorkCompleted(); | |
770 return; | |
771 } | |
772 | |
773 endpoint_desc->address = endpoint->GetAddress(); | |
774 endpoint_desc->type = type; | |
775 endpoint_desc->direction = direction; | |
776 endpoint_desc->maximum_packet_size = endpoint->GetMaximumPacketSize(); | |
777 endpoint_desc->synchronization = synchronization; | |
778 endpoint_desc->usage = usage; | |
779 | |
780 int* polling_interval = new int; | |
781 endpoint_desc->polling_interval.reset(polling_interval); | |
782 *polling_interval = endpoint->GetPollingInterval(); | |
783 | |
784 endpoints.push_back(endpoint_desc); | |
785 } | |
786 | |
787 result_->Append(PopulateInterfaceDescriptor( | |
788 descriptor->GetInterfaceNumber(), | |
789 descriptor->GetAlternateSetting(), | |
790 descriptor->GetInterfaceClass(), | |
791 descriptor->GetInterfaceSubclass(), | |
792 descriptor->GetInterfaceProtocol(), | |
793 &endpoints)); | |
794 } | |
795 } | |
796 | |
797 SetResult(result_.release()); | |
798 AsyncWorkCompleted(); | |
799 } | |
800 | |
801 bool UsbListInterfacesFunction::ConvertDirectionSafely( | |
802 const UsbEndpointDirection& input, | |
803 usb::Direction* output) { | |
804 const bool converted = ConvertDirectionToApi(input, output); | |
805 if (!converted) | |
806 SetError(kErrorConvertDirection); | |
807 return converted; | |
808 } | |
809 | |
810 bool UsbListInterfacesFunction::ConvertSynchronizationTypeSafely( | |
811 const UsbSynchronizationType& input, | |
812 usb::SynchronizationType* output) { | |
813 const bool converted = ConvertSynchronizationTypeToApi(input, output); | |
814 if (!converted) | |
815 SetError(kErrorConvertSynchronizationType); | |
816 return converted; | |
817 } | |
818 | |
819 bool UsbListInterfacesFunction::ConvertTransferTypeSafely( | |
820 const UsbTransferType& input, | |
821 usb::TransferType* output) { | |
822 const bool converted = ConvertTransferTypeToApi(input, output); | |
823 if (!converted) | |
824 SetError(kErrorConvertTransferType); | |
825 return converted; | |
826 } | |
827 | |
828 bool UsbListInterfacesFunction::ConvertUsageTypeSafely( | |
829 const UsbUsageType& input, | |
830 usb::UsageType* output) { | |
831 const bool converted = ConvertUsageTypeToApi(input, output); | |
832 if (!converted) | |
833 SetError(kErrorConvertUsageType); | |
834 return converted; | |
835 } | |
836 | |
837 UsbCloseDeviceFunction::UsbCloseDeviceFunction() {} | |
838 | |
839 UsbCloseDeviceFunction::~UsbCloseDeviceFunction() {} | |
840 | |
841 bool UsbCloseDeviceFunction::Prepare() { | |
842 parameters_ = CloseDevice::Params::Create(*args_); | |
843 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
844 return true; | |
845 } | |
846 | |
847 void UsbCloseDeviceFunction::AsyncWorkStart() { | |
848 scoped_refptr<UsbDeviceHandle> device_handle = | |
849 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
850 if (!device_handle) return; | |
851 | |
852 device_handle->Close(); | |
853 RemoveUsbDeviceResource(parameters_->handle.handle); | |
854 AsyncWorkCompleted(); | |
855 } | |
856 | |
857 UsbClaimInterfaceFunction::UsbClaimInterfaceFunction() {} | |
858 | |
859 UsbClaimInterfaceFunction::~UsbClaimInterfaceFunction() {} | |
860 | |
861 bool UsbClaimInterfaceFunction::Prepare() { | |
862 parameters_ = ClaimInterface::Params::Create(*args_); | |
863 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
864 return true; | |
865 } | |
866 | |
867 void UsbClaimInterfaceFunction::AsyncWorkStart() { | |
868 scoped_refptr<UsbDeviceHandle> device_handle = | |
869 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
870 if (!device_handle) return; | |
871 | |
872 bool success = device_handle->ClaimInterface(parameters_->interface_number); | |
873 | |
874 if (!success) | |
875 SetError(kErrorCannotClaimInterface); | |
876 AsyncWorkCompleted(); | |
877 } | |
878 | |
879 UsbReleaseInterfaceFunction::UsbReleaseInterfaceFunction() {} | |
880 | |
881 UsbReleaseInterfaceFunction::~UsbReleaseInterfaceFunction() {} | |
882 | |
883 bool UsbReleaseInterfaceFunction::Prepare() { | |
884 parameters_ = ReleaseInterface::Params::Create(*args_); | |
885 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
886 return true; | |
887 } | |
888 | |
889 void UsbReleaseInterfaceFunction::AsyncWorkStart() { | |
890 scoped_refptr<UsbDeviceHandle> device_handle = | |
891 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
892 if (!device_handle) return; | |
893 | |
894 bool success = device_handle->ReleaseInterface(parameters_->interface_number); | |
895 if (!success) | |
896 SetError(kErrorCannotReleaseInterface); | |
897 AsyncWorkCompleted(); | |
898 } | |
899 | |
900 UsbSetInterfaceAlternateSettingFunction:: | |
901 UsbSetInterfaceAlternateSettingFunction() {} | |
902 | |
903 UsbSetInterfaceAlternateSettingFunction:: | |
904 ~UsbSetInterfaceAlternateSettingFunction() {} | |
905 | |
906 bool UsbSetInterfaceAlternateSettingFunction::Prepare() { | |
907 parameters_ = SetInterfaceAlternateSetting::Params::Create(*args_); | |
908 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
909 return true; | |
910 } | |
911 | |
912 void UsbSetInterfaceAlternateSettingFunction::AsyncWorkStart() { | |
913 scoped_refptr<UsbDeviceHandle> device_handle = | |
914 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
915 if (!device_handle) return; | |
916 | |
917 bool success = device_handle->SetInterfaceAlternateSetting( | |
918 parameters_->interface_number, | |
919 parameters_->alternate_setting); | |
920 if (!success) | |
921 SetError(kErrorCannotSetInterfaceAlternateSetting); | |
922 | |
923 AsyncWorkCompleted(); | |
924 } | |
925 | |
926 UsbControlTransferFunction::UsbControlTransferFunction() {} | |
927 | |
928 UsbControlTransferFunction::~UsbControlTransferFunction() {} | |
929 | |
930 bool UsbControlTransferFunction::Prepare() { | |
931 parameters_ = ControlTransfer::Params::Create(*args_); | |
932 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
933 return true; | |
934 } | |
935 | |
936 void UsbControlTransferFunction::AsyncWorkStart() { | |
937 scoped_refptr<UsbDeviceHandle> device_handle = | |
938 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
939 if (!device_handle) return; | |
940 | |
941 const ControlTransferInfo& transfer = parameters_->transfer_info; | |
942 | |
943 UsbEndpointDirection direction; | |
944 UsbDeviceHandle::TransferRequestType request_type; | |
945 UsbDeviceHandle::TransferRecipient recipient; | |
946 size_t size = 0; | |
947 | |
948 if (!ConvertDirectionSafely(transfer.direction, &direction) || | |
949 !ConvertRequestTypeSafely(transfer.request_type, &request_type) || | |
950 !ConvertRecipientSafely(transfer.recipient, &recipient)) { | |
951 AsyncWorkCompleted(); | |
952 return; | |
953 } | |
954 | |
955 if (!GetTransferSize(transfer, &size)) { | |
956 CompleteWithError(kErrorInvalidTransferLength); | |
957 return; | |
958 } | |
959 | |
960 scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer( | |
961 transfer, direction, size); | |
962 if (!buffer.get()) { | |
963 CompleteWithError(kErrorMalformedParameters); | |
964 return; | |
965 } | |
966 | |
967 device_handle->ControlTransfer( | |
968 direction, | |
969 request_type, | |
970 recipient, | |
971 transfer.request, | |
972 transfer.value, | |
973 transfer.index, | |
974 buffer.get(), | |
975 size, | |
976 0, | |
977 base::Bind(&UsbControlTransferFunction::OnCompleted, this)); | |
978 } | |
979 | |
980 UsbBulkTransferFunction::UsbBulkTransferFunction() {} | |
981 | |
982 UsbBulkTransferFunction::~UsbBulkTransferFunction() {} | |
983 | |
984 bool UsbBulkTransferFunction::Prepare() { | |
985 parameters_ = BulkTransfer::Params::Create(*args_); | |
986 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
987 return true; | |
988 } | |
989 | |
990 void UsbBulkTransferFunction::AsyncWorkStart() { | |
991 scoped_refptr<UsbDeviceHandle> device_handle = | |
992 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
993 if (!device_handle) return; | |
994 | |
995 const GenericTransferInfo& transfer = parameters_->transfer_info; | |
996 | |
997 UsbEndpointDirection direction; | |
998 size_t size = 0; | |
999 | |
1000 if (!ConvertDirectionSafely(transfer.direction, &direction)) { | |
1001 AsyncWorkCompleted(); | |
1002 return; | |
1003 } | |
1004 | |
1005 if (!GetTransferSize(transfer, &size)) { | |
1006 CompleteWithError(kErrorInvalidTransferLength); | |
1007 return; | |
1008 } | |
1009 | |
1010 scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer( | |
1011 transfer, direction, size); | |
1012 if (!buffer.get()) { | |
1013 CompleteWithError(kErrorMalformedParameters); | |
1014 return; | |
1015 } | |
1016 | |
1017 device_handle->BulkTransfer( | |
1018 direction, | |
1019 transfer.endpoint, | |
1020 buffer.get(), | |
1021 size, | |
1022 0, | |
1023 base::Bind(&UsbBulkTransferFunction::OnCompleted, this)); | |
1024 } | |
1025 | |
1026 UsbInterruptTransferFunction::UsbInterruptTransferFunction() {} | |
1027 | |
1028 UsbInterruptTransferFunction::~UsbInterruptTransferFunction() {} | |
1029 | |
1030 bool UsbInterruptTransferFunction::Prepare() { | |
1031 parameters_ = InterruptTransfer::Params::Create(*args_); | |
1032 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
1033 return true; | |
1034 } | |
1035 | |
1036 void UsbInterruptTransferFunction::AsyncWorkStart() { | |
1037 scoped_refptr<UsbDeviceHandle> device_handle = | |
1038 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
1039 if (!device_handle) return; | |
1040 | |
1041 const GenericTransferInfo& transfer = parameters_->transfer_info; | |
1042 | |
1043 UsbEndpointDirection direction; | |
1044 size_t size = 0; | |
1045 | |
1046 if (!ConvertDirectionSafely(transfer.direction, &direction)) { | |
1047 AsyncWorkCompleted(); | |
1048 return; | |
1049 } | |
1050 | |
1051 if (!GetTransferSize(transfer, &size)) { | |
1052 CompleteWithError(kErrorInvalidTransferLength); | |
1053 return; | |
1054 } | |
1055 | |
1056 scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer( | |
1057 transfer, direction, size); | |
1058 if (!buffer.get()) { | |
1059 CompleteWithError(kErrorMalformedParameters); | |
1060 return; | |
1061 } | |
1062 | |
1063 device_handle->InterruptTransfer( | |
1064 direction, | |
1065 transfer.endpoint, | |
1066 buffer.get(), | |
1067 size, | |
1068 0, | |
1069 base::Bind(&UsbInterruptTransferFunction::OnCompleted, this)); | |
1070 } | |
1071 | |
1072 UsbIsochronousTransferFunction::UsbIsochronousTransferFunction() {} | |
1073 | |
1074 UsbIsochronousTransferFunction::~UsbIsochronousTransferFunction() {} | |
1075 | |
1076 bool UsbIsochronousTransferFunction::Prepare() { | |
1077 parameters_ = IsochronousTransfer::Params::Create(*args_); | |
1078 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
1079 return true; | |
1080 } | |
1081 | |
1082 void UsbIsochronousTransferFunction::AsyncWorkStart() { | |
1083 scoped_refptr<UsbDeviceHandle> device_handle = | |
1084 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
1085 if (!device_handle) return; | |
1086 | |
1087 const IsochronousTransferInfo& transfer = parameters_->transfer_info; | |
1088 const GenericTransferInfo& generic_transfer = transfer.transfer_info; | |
1089 | |
1090 size_t size = 0; | |
1091 UsbEndpointDirection direction; | |
1092 | |
1093 if (!ConvertDirectionSafely(generic_transfer.direction, &direction)) { | |
1094 AsyncWorkCompleted(); | |
1095 return; | |
1096 } | |
1097 if (!GetTransferSize(generic_transfer, &size)) { | |
1098 CompleteWithError(kErrorInvalidTransferLength); | |
1099 return; | |
1100 } | |
1101 if (transfer.packets < 0 || transfer.packets >= kMaxPackets) { | |
1102 CompleteWithError(kErrorInvalidNumberOfPackets); | |
1103 return; | |
1104 } | |
1105 unsigned int packets = transfer.packets; | |
1106 if (transfer.packet_length < 0 || | |
1107 transfer.packet_length >= kMaxPacketLength) { | |
1108 CompleteWithError(kErrorInvalidPacketLength); | |
1109 return; | |
1110 } | |
1111 unsigned int packet_length = transfer.packet_length; | |
1112 const uint64 total_length = packets * packet_length; | |
1113 if (packets > size || total_length > size) { | |
1114 CompleteWithError(kErrorTransferLength); | |
1115 return; | |
1116 } | |
1117 | |
1118 scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer( | |
1119 generic_transfer, direction, size); | |
1120 if (!buffer.get()) { | |
1121 CompleteWithError(kErrorMalformedParameters); | |
1122 return; | |
1123 } | |
1124 | |
1125 device_handle->IsochronousTransfer( | |
1126 direction, | |
1127 generic_transfer.endpoint, | |
1128 buffer.get(), | |
1129 size, | |
1130 packets, | |
1131 packet_length, | |
1132 0, | |
1133 base::Bind(&UsbIsochronousTransferFunction::OnCompleted, this)); | |
1134 } | |
1135 | |
1136 UsbResetDeviceFunction::UsbResetDeviceFunction() {} | |
1137 | |
1138 UsbResetDeviceFunction::~UsbResetDeviceFunction() {} | |
1139 | |
1140 bool UsbResetDeviceFunction::Prepare() { | |
1141 parameters_ = ResetDevice::Params::Create(*args_); | |
1142 EXTENSION_FUNCTION_VALIDATE(parameters_.get()); | |
1143 return true; | |
1144 } | |
1145 | |
1146 void UsbResetDeviceFunction::AsyncWorkStart() { | |
1147 scoped_refptr<UsbDeviceHandle> device_handle = | |
1148 GetDeviceHandleOrCompleteWithError(parameters_->handle); | |
1149 if (!device_handle) return; | |
1150 | |
1151 bool success = device_handle->ResetDevice(); | |
1152 if (!success) { | |
1153 device_handle->Close(); | |
1154 RemoveUsbDeviceResource(parameters_->handle.handle); | |
1155 SetResult(new base::FundamentalValue(false)); | |
1156 CompleteWithError(kErrorResetDevice); | |
1157 return; | |
1158 } | |
1159 | |
1160 SetResult(new base::FundamentalValue(true)); | |
1161 AsyncWorkCompleted(); | |
1162 } | |
1163 | |
1164 } // namespace extensions | |
OLD | NEW |