Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(116)

Unified Diff: chrome/browser/usb/usb_device_handle.cc

Issue 16316004: Separate usb device handle from usb device. (deprecate) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Windows compile and a bug. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/usb/usb_device_handle.cc
diff --git a/chrome/browser/usb/usb_device.cc b/chrome/browser/usb/usb_device_handle.cc
similarity index 61%
rename from chrome/browser/usb/usb_device.cc
rename to chrome/browser/usb/usb_device_handle.cc
index 13fc395f3d5bbc0fffc54fb4c2ab6f0b3c24b0a4..15dc3b4f5a2861029ad237c4c450ad5686dc26a7 100644
--- a/chrome/browser/usb/usb_device.cc
+++ b/chrome/browser/usb/usb_device_handle.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/usb/usb_device.h"
+#include "chrome/browser/usb/usb_device_handle.h"
#include <vector>
@@ -10,8 +10,28 @@
#include "base/synchronization/lock.h"
#include "chrome/browser/usb/usb_interface.h"
#include "chrome/browser/usb/usb_service.h"
+#include "content/public/browser/browser_thread.h"
#include "third_party/libusb/src/libusb/libusb.h"
+using content::BrowserThread;
+
+#define CHECK_DEVICE(callback, args...) \
+ do { \
+ if (handle_ == NULL) { \
+ DVLOG(1) << "Device is disconnected: "; \
+ callback.Run(args);\
+ return; \
+ } \
+ } while (0)
+
+#define CHECK_DEVICE_RETURN \
+ do { \
+ if (handle_ == NULL) { \
+ DVLOG(1) << "Device is disconnected: "; \
+ return; \
+ } \
+ } while (0)
+
namespace {
static uint8 ConvertTransferDirection(
@@ -28,36 +48,36 @@ static uint8 ConvertTransferDirection(
}
static uint8 CreateRequestType(const UsbEndpointDirection direction,
- const UsbDevice::TransferRequestType request_type,
- const UsbDevice::TransferRecipient recipient) {
+ const UsbDeviceHandle::TransferRequestType request_type,
+ const UsbDeviceHandle::TransferRecipient recipient) {
uint8 result = ConvertTransferDirection(direction);
switch (request_type) {
- case UsbDevice::STANDARD:
+ case UsbDeviceHandle::STANDARD:
result |= LIBUSB_REQUEST_TYPE_STANDARD;
break;
- case UsbDevice::CLASS:
+ case UsbDeviceHandle::CLASS:
result |= LIBUSB_REQUEST_TYPE_CLASS;
break;
- case UsbDevice::VENDOR:
+ case UsbDeviceHandle::VENDOR:
result |= LIBUSB_REQUEST_TYPE_VENDOR;
break;
- case UsbDevice::RESERVED:
+ case UsbDeviceHandle::RESERVED:
result |= LIBUSB_REQUEST_TYPE_RESERVED;
break;
}
switch (recipient) {
- case UsbDevice::DEVICE:
+ case UsbDeviceHandle::DEVICE:
result |= LIBUSB_RECIPIENT_DEVICE;
break;
- case UsbDevice::INTERFACE:
+ case UsbDeviceHandle::INTERFACE:
result |= LIBUSB_RECIPIENT_INTERFACE;
break;
- case UsbDevice::ENDPOINT:
+ case UsbDeviceHandle::ENDPOINT:
result |= LIBUSB_RECIPIENT_ENDPOINT;
break;
- case UsbDevice::OTHER:
+ case UsbDeviceHandle::OTHER:
result |= LIBUSB_RECIPIENT_OTHER;
break;
}
@@ -88,59 +108,93 @@ static UsbTransferStatus ConvertTransferStatus(
}
}
+// This function dispatches a completed transfer to its handle.
+// It is called from UsbEventDispatcher using libusb_handle_events_timeout.
static void LIBUSB_CALL HandleTransferCompletion(
struct libusb_transfer* transfer) {
- UsbDevice* const device = reinterpret_cast<UsbDevice*>(transfer->user_data);
+ UsbDeviceHandle* const device =
+ reinterpret_cast<UsbDeviceHandle*>(transfer->user_data);
+
device->TransferComplete(transfer);
+ libusb_free_transfer(transfer);
}
} // namespace
-UsbDevice::Transfer::Transfer() : length(0) {}
+UsbDeviceHandle::Transfer::Transfer()
+ : transfer_type(USB_TRANSFER_CONTROL), length(0) {}
-UsbDevice::Transfer::~Transfer() {}
+UsbDeviceHandle::Transfer::~Transfer() {}
-UsbDevice::UsbDevice(UsbService* service, PlatformUsbDeviceHandle handle)
- : service_(service), handle_(handle) {
+UsbDeviceHandle::UsbDeviceHandle(UsbService* service,
+ int device,
+ PlatformUsbDeviceHandle handle)
+ : service_(service), device_(device), handle_(handle) {
DCHECK(handle) << "Cannot create device with NULL handle.";
}
-UsbDevice::UsbDevice() : service_(NULL), handle_(NULL) {}
+UsbDeviceHandle::UsbDeviceHandle()
+ : service_(NULL), device_(0), handle_(NULL) {
+}
-UsbDevice::~UsbDevice() {}
+UsbDeviceHandle::~UsbDeviceHandle() {
+ InternalClose();
+}
-void UsbDevice::Close(const base::Callback<void()>& callback) {
- CheckDevice();
- service_->CloseDevice(this);
- handle_ = NULL;
- callback.Run();
+void UsbDeviceHandle::Close(const base::Callback<void()>& callback) {
+ if (handle_ == 0)
+ return;
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&UsbService::CloseDeviceHandle,
+ base::Unretained(service_),
+ make_scoped_refptr(this),
+ callback));
}
-void UsbDevice::TransferComplete(PlatformUsbTransferHandle handle) {
- base::AutoLock lock(lock_);
+void UsbDeviceHandle::TransferComplete(PlatformUsbTransferHandle handle) {
+ Transfer transfer;
+ base::AutoLock handle_guard(handle_lock_);
+ // If handle->user_data is cleared after we obtained it, the handles will be
+ // removed and callbacks is already called in InternalClose. This case we can
+ // simply return.
+ if (handle->user_data == NULL)
+ return;
+
+ {
+ base::AutoLock guard(transfer_lock_);
+ transfer = transfers_[handle];
+ transfers_.erase(handle);
+ }
- // TODO(gdk): Handle device disconnect.
- DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed";
- Transfer* const transfer = &transfers_[handle];
+ CHECK_DEVICE(transfer.callback,
+ USB_TRANSFER_DISCONNECT,
+ scoped_refptr<net::IOBuffer>(), 0);
+
+ if (handle->status != LIBUSB_TRANSFER_COMPLETED &&
+ handle->status != LIBUSB_TRANSFER_CANCELLED) {
+ service_->ScheduleEnumerateDevice();
+ }
DCHECK(handle->actual_length >= 0) << "Negative actual length received";
size_t actual_length =
static_cast<size_t>(std::max(handle->actual_length, 0));
- DCHECK(transfer->length >= actual_length) <<
+ DCHECK(transfer.length >= actual_length) <<
"data too big for our buffer (libusb failure?)";
- scoped_refptr<net::IOBuffer> buffer = transfer->buffer;
- switch (transfer->transfer_type) {
+ scoped_refptr<net::IOBuffer> buffer = transfer.buffer;
+ switch (transfer.transfer_type) {
case USB_TRANSFER_CONTROL:
// If the transfer is a control transfer we do not expose the control
// setup header to the caller. This logic strips off the header if
// present before invoking the callback provided with the transfer.
if (actual_length > 0) {
- CHECK(transfer->length >= LIBUSB_CONTROL_SETUP_SIZE) <<
+ CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) <<
"buffer was not correctly set: too small for the control header";
- if (transfer->length >= actual_length &&
+ if (transfer.length >= actual_length &&
actual_length >= LIBUSB_CONTROL_SETUP_SIZE) {
// If the payload is zero bytes long, pad out the allocated buffer
// size to one byte so that an IOBuffer of that size can be allocated.
@@ -168,7 +222,7 @@ void UsbDevice::TransferComplete(PlatformUsbTransferHandle handle) {
// all the data the packet can hold.
if (actual_length < packet_buffer_start) {
CHECK(packet_buffer_start + packet->actual_length <=
- transfer->length);
+ transfer.length);
memmove(buffer->data() + actual_length,
buffer->data() + packet_buffer_start,
packet->actual_length);
@@ -189,16 +243,13 @@ void UsbDevice::TransferComplete(PlatformUsbTransferHandle handle) {
NOTREACHED() << "Invalid usb transfer type";
}
- transfer->callback.Run(ConvertTransferStatus(handle->status), buffer,
- actual_length);
-
- transfers_.erase(handle);
- libusb_free_transfer(handle);
+ transfer.callback.Run(ConvertTransferStatus(handle->status), buffer,
+ actual_length);
}
-void UsbDevice::ListInterfaces(UsbConfigDescriptor* config,
- const UsbInterfaceCallback& callback) {
- CheckDevice();
+void UsbDeviceHandle::ListInterfaces(UsbConfigDescriptor* config,
+ const UsbInterfaceCallback& callback) {
+ CHECK_DEVICE(callback, false);
PlatformUsbDevice device = libusb_get_device(handle_);
@@ -211,28 +262,28 @@ void UsbDevice::ListInterfaces(UsbConfigDescriptor* config,
callback.Run(list_result == 0);
}
-void UsbDevice::ClaimInterface(const int interface_number,
- const UsbInterfaceCallback& callback) {
- CheckDevice();
+void UsbDeviceHandle::ClaimInterface(const int interface_number,
+ const UsbInterfaceCallback& callback) {
+ CHECK_DEVICE(callback, false);
const int claim_result = libusb_claim_interface(handle_, interface_number);
callback.Run(claim_result == 0);
}
-void UsbDevice::ReleaseInterface(const int interface_number,
+void UsbDeviceHandle::ReleaseInterface(const int interface_number,
const UsbInterfaceCallback& callback) {
- CheckDevice();
+ CHECK_DEVICE(callback, false);
const int release_result = libusb_release_interface(handle_,
interface_number);
callback.Run(release_result == 0);
}
-void UsbDevice::SetInterfaceAlternateSetting(
+void UsbDeviceHandle::SetInterfaceAlternateSetting(
const int interface_number,
const int alternate_setting,
const UsbInterfaceCallback& callback) {
- CheckDevice();
+ CHECK_DEVICE(callback, false);
const int setting_result = libusb_set_interface_alt_setting(handle_,
interface_number, alternate_setting);
@@ -240,12 +291,13 @@ void UsbDevice::SetInterfaceAlternateSetting(
callback.Run(setting_result == 0);
}
-void UsbDevice::ControlTransfer(const UsbEndpointDirection direction,
+void UsbDeviceHandle::ControlTransfer(const UsbEndpointDirection direction,
const TransferRequestType request_type, const TransferRecipient recipient,
const uint8 request, const uint16 value, const uint16 index,
net::IOBuffer* buffer, const size_t length, const unsigned int timeout,
const UsbTransferCallback& callback) {
- CheckDevice();
+ CHECK_DEVICE(callback, USB_TRANSFER_DISCONNECT,
+ scoped_refptr<net::IOBuffer>(), 0);
const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
scoped_refptr<net::IOBuffer> resized_buffer(new net::IOBufferWithSize(
@@ -267,10 +319,11 @@ void UsbDevice::ControlTransfer(const UsbEndpointDirection direction,
callback);
}
-void UsbDevice::BulkTransfer(const UsbEndpointDirection direction,
+void UsbDeviceHandle::BulkTransfer(const UsbEndpointDirection direction,
const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
const unsigned int timeout, const UsbTransferCallback& callback) {
- CheckDevice();
+ CHECK_DEVICE(callback, USB_TRANSFER_DISCONNECT,
+ scoped_refptr<net::IOBuffer>(), 0);
struct libusb_transfer* const transfer = libusb_alloc_transfer(0);
const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
@@ -280,10 +333,11 @@ void UsbDevice::BulkTransfer(const UsbEndpointDirection direction,
SubmitTransfer(transfer, USB_TRANSFER_BULK, buffer, length, callback);
}
-void UsbDevice::InterruptTransfer(const UsbEndpointDirection direction,
+void UsbDeviceHandle::InterruptTransfer(const UsbEndpointDirection direction,
const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
const unsigned int timeout, const UsbTransferCallback& callback) {
- CheckDevice();
+ CHECK_DEVICE(callback, USB_TRANSFER_DISCONNECT,
+ scoped_refptr<net::IOBuffer>(), 0);
struct libusb_transfer* const transfer = libusb_alloc_transfer(0);
const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
@@ -293,11 +347,12 @@ void UsbDevice::InterruptTransfer(const UsbEndpointDirection direction,
SubmitTransfer(transfer, USB_TRANSFER_INTERRUPT, buffer, length, callback);
}
-void UsbDevice::IsochronousTransfer(const UsbEndpointDirection direction,
+void UsbDeviceHandle::IsochronousTransfer(const UsbEndpointDirection direction,
const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
const unsigned int packets, const unsigned int packet_length,
const unsigned int timeout, const UsbTransferCallback& callback) {
- CheckDevice();
+ CHECK_DEVICE(callback, USB_TRANSFER_DISCONNECT,
+ scoped_refptr<net::IOBuffer>(), 0);
const uint64 total_length = packets * packet_length;
CHECK(packets <= length && total_length <= length) <<
@@ -313,29 +368,47 @@ void UsbDevice::IsochronousTransfer(const UsbEndpointDirection direction,
SubmitTransfer(transfer, USB_TRANSFER_ISOCHRONOUS, buffer, length, callback);
}
-void UsbDevice::ResetDevice(const base::Callback<void(bool)>& callback) {
- CheckDevice();
+void UsbDeviceHandle::ResetDevice(const base::Callback<void(bool)>& callback) {
+ // Blocking operation. Run it on the FILE thread.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ CHECK_DEVICE(callback, false);
callback.Run(libusb_reset_device(handle_) == 0);
}
-void UsbDevice::CheckDevice() {
- DCHECK(handle_) << "Device is already closed.";
+void UsbDeviceHandle::InternalClose() {
+ base::AutoLock handle_guard(handle_lock_);
+ base::AutoLock guard(transfer_lock_);
+ if (handle_ == NULL)
+ return;
+
+ // Cancel all the transfers.
+ for (std::map<PlatformUsbTransferHandle, Transfer>::iterator it
+ = transfers_.begin(); it != transfers_.end(); it++) {
+ it->first->user_data = NULL;
+ it->second.callback.Run(USB_TRANSFER_DISCONNECT,
+ scoped_refptr<net::IOBuffer>(), 0);
+ }
+ transfers_.clear();
+ libusb_close(handle_);
+ handle_ = NULL;
}
-void UsbDevice::SubmitTransfer(PlatformUsbTransferHandle handle,
- UsbTransferType transfer_type,
- net::IOBuffer* buffer,
- const size_t length,
- const UsbTransferCallback& callback) {
+void UsbDeviceHandle::SubmitTransfer(PlatformUsbTransferHandle handle,
+ UsbTransferType transfer_type,
+ net::IOBuffer* buffer,
+ const size_t length,
+ const UsbTransferCallback& callback) {
+ base::AutoLock lock(transfer_lock_);
+ // This check must be done after the lock.
+ if (!handle_)
+ return;
+
Transfer transfer;
transfer.transfer_type = transfer_type;
transfer.buffer = buffer;
transfer.length = length;
transfer.callback = callback;
- {
- base::AutoLock lock(lock_);
- transfers_[handle] = transfer;
- libusb_submit_transfer(handle);
- }
+ transfers_[handle] = transfer;
+ libusb_submit_transfer(handle);
}

Powered by Google App Engine
This is Rietveld 408576698