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

Side by Side Diff: chrome/browser/usb/usb_device_handle.cc

Issue 22492003: Fixes leaking transfer objects due to improper USB handle closure. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Minor fix Created 7 years, 4 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/usb/usb_device_handle.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "chrome/browser/usb/usb_device_handle.h" 5 #include "chrome/browser/usb/usb_device_handle.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/message_loop/message_loop.h"
10 #include "base/stl_util.h" 11 #include "base/stl_util.h"
11 #include "base/strings/string16.h" 12 #include "base/strings/string16.h"
12 #include "base/synchronization/lock.h" 13 #include "base/synchronization/lock.h"
14 #include "chrome/browser/usb/usb_context.h"
13 #include "chrome/browser/usb/usb_device.h" 15 #include "chrome/browser/usb/usb_device.h"
14 #include "chrome/browser/usb/usb_interface.h" 16 #include "chrome/browser/usb/usb_interface.h"
15 #include "chrome/browser/usb/usb_service.h" 17 #include "chrome/browser/usb/usb_service.h"
16 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
17 #include "third_party/libusb/src/libusb/libusb.h" 19 #include "third_party/libusb/src/libusb/libusb.h"
18 20
19 using content::BrowserThread; 21 using content::BrowserThread;
22 void HandleTransferCompletion(PlatformUsbTransferHandle transfer);
20 23
21 namespace { 24 namespace {
22 25
23 static uint8 ConvertTransferDirection( 26 static uint8 ConvertTransferDirection(
24 const UsbEndpointDirection direction) { 27 const UsbEndpointDirection direction) {
25 switch (direction) { 28 switch (direction) {
26 case USB_DIRECTION_INBOUND: 29 case USB_DIRECTION_INBOUND:
27 return LIBUSB_ENDPOINT_IN; 30 return LIBUSB_ENDPOINT_IN;
28 case USB_DIRECTION_OUTBOUND: 31 case USB_DIRECTION_OUTBOUND:
29 return LIBUSB_ENDPOINT_OUT; 32 return LIBUSB_ENDPOINT_OUT;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 case LIBUSB_TRANSFER_OVERFLOW: 90 case LIBUSB_TRANSFER_OVERFLOW:
88 return USB_TRANSFER_OVERFLOW; 91 return USB_TRANSFER_OVERFLOW;
89 case LIBUSB_TRANSFER_CANCELLED: 92 case LIBUSB_TRANSFER_CANCELLED:
90 return USB_TRANSFER_CANCELLED; 93 return USB_TRANSFER_CANCELLED;
91 default: 94 default:
92 NOTREACHED(); 95 NOTREACHED();
93 return USB_TRANSFER_ERROR; 96 return USB_TRANSFER_ERROR;
94 } 97 }
95 } 98 }
96 99
97 static void LIBUSB_CALL HandleTransferCompletion( 100 static void LIBUSB_CALL PlatformTransferCompletionCallback(
98 struct libusb_transfer* transfer) { 101 PlatformUsbTransferHandle transfer) {
99 UsbDeviceHandle* const device = 102 BrowserThread::PostTask(BrowserThread::FILE,
100 reinterpret_cast<UsbDeviceHandle*>(transfer->user_data); 103 FROM_HERE,
101 device->TransferComplete(transfer); 104 base::Bind(HandleTransferCompletion, transfer));
102 } 105 }
103 106
104 } // namespace 107 } // namespace
105 108
109 void HandleTransferCompletion(PlatformUsbTransferHandle transfer) {
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
111 UsbDeviceHandle* const device_handle =
112 reinterpret_cast<UsbDeviceHandle*>(transfer->user_data);
113 CHECK(device_handle) << "Device handle is closed before transfer finishes.";
114 device_handle->TransferComplete(transfer);
115 libusb_free_transfer(transfer);
116 }
117
118
119 class UsbDeviceHandle::InterfaceClaimer
120 : public base::RefCountedThreadSafe<UsbDeviceHandle::InterfaceClaimer> {
121 public:
122 InterfaceClaimer(const scoped_refptr<UsbDeviceHandle> handle,
123 const int interface_number);
124
125 bool Claim() const;
126
127 int alternate_setting() const { return alternate_setting_; }
128 void set_alternate_setting(const int alternate_setting) {
129 alternate_setting_ = alternate_setting;
130 }
131
132 private:
133 friend class UsbDevice;
134 friend class base::RefCountedThreadSafe<InterfaceClaimer>;
135 ~InterfaceClaimer();
136
137 const scoped_refptr<UsbDeviceHandle> handle_;
138 const int interface_number_;
139 int alternate_setting_;
140
141 DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer);
142 };
143
144 UsbDeviceHandle::InterfaceClaimer::InterfaceClaimer(
145 const scoped_refptr<UsbDeviceHandle> handle, const int interface_number)
146 : handle_(handle),
147 interface_number_(interface_number),
148 alternate_setting_(0) {
149 }
150
151 UsbDeviceHandle::InterfaceClaimer::~InterfaceClaimer() {
152 libusb_release_interface(handle_->handle(), interface_number_);
153 }
154
155 bool UsbDeviceHandle::InterfaceClaimer::Claim() const {
156 return libusb_claim_interface(handle_->handle(), interface_number_) == 0;
157 }
158
159 struct UsbDeviceHandle::Transfer {
160 Transfer();
161 ~Transfer();
162
163 UsbTransferType transfer_type;
164 scoped_refptr<net::IOBuffer> buffer;
165 scoped_refptr<UsbDeviceHandle::InterfaceClaimer> claimed_interface;
166 scoped_refptr<base::MessageLoopProxy> message_loop_proxy;
167 size_t length;
168 UsbTransferCallback callback;
169 };
170
106 UsbDeviceHandle::Transfer::Transfer() 171 UsbDeviceHandle::Transfer::Transfer()
107 : transfer_type(USB_TRANSFER_CONTROL), 172 : transfer_type(USB_TRANSFER_CONTROL),
108 length(0) { 173 length(0) {
109 } 174 }
110 175
111 UsbDeviceHandle::Transfer::~Transfer() {} 176 UsbDeviceHandle::Transfer::~Transfer() {}
112 177
113 UsbDeviceHandle::UsbDeviceHandle( 178 UsbDeviceHandle::UsbDeviceHandle(
179 scoped_refptr<UsbContext> context,
114 UsbDevice* device, 180 UsbDevice* device,
115 PlatformUsbDeviceHandle handle) 181 PlatformUsbDeviceHandle handle)
116 : device_(device), handle_(handle) { 182 : device_(device), handle_(handle), context_(context) {
117 DCHECK(thread_checker_.CalledOnValidThread()); 183 DCHECK(thread_checker_.CalledOnValidThread());
118 DCHECK(handle) << "Cannot create device with NULL handle."; 184 DCHECK(handle) << "Cannot create device with NULL handle.";
185 interfaces_ = new UsbConfigDescriptor();
186 device->ListInterfaces(interfaces_.get());
119 } 187 }
120 188
121 UsbDeviceHandle::UsbDeviceHandle() : device_(NULL), handle_(NULL) { 189 UsbDeviceHandle::UsbDeviceHandle() : device_(NULL), handle_(NULL) {
122 } 190 }
123 191
124 UsbDeviceHandle::~UsbDeviceHandle() { 192 UsbDeviceHandle::~UsbDeviceHandle() {
125 DCHECK(thread_checker_.CalledOnValidThread()); 193 DCHECK(thread_checker_.CalledOnValidThread());
126 Close(); 194
195 libusb_close(handle_);
196 handle_ = NULL;
127 } 197 }
128 198
129 scoped_refptr<UsbDevice> UsbDeviceHandle::device() const { 199 scoped_refptr<UsbDevice> UsbDeviceHandle::device() const {
130 return device_; 200 return device_;
131 } 201 }
132 202
133 void UsbDeviceHandle::Close() { 203 void UsbDeviceHandle::Close() {
134 DCHECK(thread_checker_.CalledOnValidThread()); 204 DCHECK(thread_checker_.CalledOnValidThread());
135 if (handle_) 205 if (device_)
136 device_->Close(this); 206 device_->Close(this);
137 } 207 }
138 208
139 void UsbDeviceHandle::TransferComplete(PlatformUsbTransferHandle handle) { 209 void UsbDeviceHandle::TransferComplete(PlatformUsbTransferHandle handle) {
140 base::AutoLock lock(lock_); 210 DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed";
141 211
142 // TODO(gdk): Handle device disconnect. 212 Transfer transfer = transfers_[handle];
143 DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed"; 213 transfers_.erase(handle);
144 Transfer* const transfer = &transfers_[handle];
145 214
146 DCHECK_GE(handle->actual_length, 0) << "Negative actual length received"; 215 DCHECK_GE(handle->actual_length, 0) << "Negative actual length received";
147 size_t actual_length = 216 size_t actual_length =
148 static_cast<size_t>(std::max(handle->actual_length, 0)); 217 static_cast<size_t>(std::max(handle->actual_length, 0));
149 218
150 DCHECK(transfer->length >= actual_length) << 219 DCHECK(transfer.length >= actual_length) <<
151 "data too big for our buffer (libusb failure?)"; 220 "data too big for our buffer (libusb failure?)";
152 221
153 scoped_refptr<net::IOBuffer> buffer = transfer->buffer; 222 scoped_refptr<net::IOBuffer> buffer = transfer.buffer;
154 switch (transfer->transfer_type) { 223 switch (transfer.transfer_type) {
155 case USB_TRANSFER_CONTROL: 224 case USB_TRANSFER_CONTROL:
156 // If the transfer is a control transfer we do not expose the control 225 // If the transfer is a control transfer we do not expose the control
157 // setup header to the caller. This logic strips off the header if 226 // setup header to the caller. This logic strips off the header if
158 // present before invoking the callback provided with the transfer. 227 // present before invoking the callback provided with the transfer.
159 if (actual_length > 0) { 228 if (actual_length > 0) {
160 CHECK(transfer->length >= LIBUSB_CONTROL_SETUP_SIZE) << 229 CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) <<
161 "buffer was not correctly set: too small for the control header"; 230 "buffer was not correctly set: too small for the control header";
162 231
163 if (transfer->length >= actual_length && 232 if (transfer.length >= actual_length &&
164 actual_length >= LIBUSB_CONTROL_SETUP_SIZE) { 233 actual_length >= LIBUSB_CONTROL_SETUP_SIZE) {
165 // If the payload is zero bytes long, pad out the allocated buffer 234 // If the payload is zero bytes long, pad out the allocated buffer
166 // size to one byte so that an IOBuffer of that size can be allocated. 235 // size to one byte so that an IOBuffer of that size can be allocated.
167 scoped_refptr<net::IOBuffer> resized_buffer = new net::IOBuffer( 236 scoped_refptr<net::IOBuffer> resized_buffer = new net::IOBuffer(
168 std::max(actual_length, static_cast<size_t>(1))); 237 std::max(actual_length, static_cast<size_t>(1)));
169 memcpy(resized_buffer->data(), 238 memcpy(resized_buffer->data(),
170 buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, 239 buffer->data() + LIBUSB_CONTROL_SETUP_SIZE,
171 actual_length); 240 actual_length);
172 buffer = resized_buffer; 241 buffer = resized_buffer;
173 } 242 }
174 } 243 }
175 break; 244 break;
176 245
177 case USB_TRANSFER_ISOCHRONOUS: 246 case USB_TRANSFER_ISOCHRONOUS:
178 // Isochronous replies might carry data in the different isoc packets even 247 // Isochronous replies might carry data in the different isoc packets even
179 // if the transfer actual_data value is zero. Furthermore, not all of the 248 // if the transfer actual_data value is zero. Furthermore, not all of the
180 // received packets might contain data, so we need to calculate how many 249 // received packets might contain data, so we need to calculate how many
181 // data bytes we are effectively providing and pack the results. 250 // data bytes we are effectively providing and pack the results.
182 if (actual_length == 0) { 251 if (actual_length == 0) {
183 size_t packet_buffer_start = 0; 252 size_t packet_buffer_start = 0;
184 for (int i = 0; i < handle->num_iso_packets; ++i) { 253 for (int i = 0; i < handle->num_iso_packets; ++i) {
185 PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i]; 254 PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i];
186 if (packet->actual_length > 0) { 255 if (packet->actual_length > 0) {
187 // We don't need to copy as long as all packets until now provide 256 // We don't need to copy as long as all packets until now provide
188 // all the data the packet can hold. 257 // all the data the packet can hold.
189 if (actual_length < packet_buffer_start) { 258 if (actual_length < packet_buffer_start) {
190 CHECK(packet_buffer_start + packet->actual_length <= 259 CHECK(packet_buffer_start + packet->actual_length <=
191 transfer->length); 260 transfer.length);
192 memmove(buffer->data() + actual_length, 261 memmove(buffer->data() + actual_length,
193 buffer->data() + packet_buffer_start, 262 buffer->data() + packet_buffer_start,
194 packet->actual_length); 263 packet->actual_length);
195 } 264 }
196 actual_length += packet->actual_length; 265 actual_length += packet->actual_length;
197 } 266 }
198 267
199 packet_buffer_start += packet->length; 268 packet_buffer_start += packet->length;
200 } 269 }
201 } 270 }
202 break; 271 break;
203 272
204 case USB_TRANSFER_BULK: 273 case USB_TRANSFER_BULK:
205 case USB_TRANSFER_INTERRUPT: 274 case USB_TRANSFER_INTERRUPT:
206 break; 275 break;
207 276
208 default: 277 default:
209 NOTREACHED() << "Invalid usb transfer type"; 278 NOTREACHED() << "Invalid usb transfer type";
210 break; 279 break;
211 } 280 }
212 281
213 transfer->callback.Run(ConvertTransferStatus(handle->status), buffer, 282 transfer.message_loop_proxy->PostTask(
214 actual_length); 283 FROM_HERE,
284 base::Bind(transfer.callback,
285 ConvertTransferStatus(handle->status),
286 buffer,
287 actual_length));
215 288
216 transfers_.erase(handle); 289 // Must release interface first before actually delete this.
217 libusb_free_transfer(handle); 290 transfer.claimed_interface = NULL;
218 } 291 }
219 292
220 bool UsbDeviceHandle::ClaimInterface(const int interface_number) { 293 bool UsbDeviceHandle::ClaimInterface(const int interface_number) {
221 DCHECK(thread_checker_.CalledOnValidThread()); 294 DCHECK(thread_checker_.CalledOnValidThread());
222 if (!handle_) return false; 295 if (!device_) return false;
296 if (ContainsKey(claimed_interfaces_, interface_number)) return true;
223 297
224 const int claim_result = libusb_claim_interface(handle_, interface_number); 298 scoped_refptr<InterfaceClaimer> claimer =
225 return claim_result == 0; 299 new InterfaceClaimer(this, interface_number);
300
301 if (claimer->Claim()) {
302 claimed_interfaces_[interface_number]= claimer;
303 RefreshEndpointMap();
304 return true;
305 }
306 return false;
226 } 307 }
227 308
228 bool UsbDeviceHandle::ReleaseInterface(const int interface_number) { 309 bool UsbDeviceHandle::ReleaseInterface(const int interface_number) {
229 DCHECK(thread_checker_.CalledOnValidThread()); 310 DCHECK(thread_checker_.CalledOnValidThread());
230 if (!handle_) return false; 311 if (!device_) return false;
312 if (!ContainsKey(claimed_interfaces_, interface_number)) return false;
231 313
232 const int release_result = libusb_release_interface(handle_, 314 // Cancel all the transfers on that interface.
233 interface_number); 315 InterfaceClaimer* interface_claimer =
234 return release_result == 0; 316 claimed_interfaces_[interface_number].get();
317 for (TransferMap::iterator it = transfers_.begin();
318 it != transfers_.end(); ++it) {
319 if (it->second.claimed_interface.get() == interface_claimer)
320 libusb_cancel_transfer(it->first);
321 }
322 claimed_interfaces_.erase(interface_number);
323
324 RefreshEndpointMap();
325 return true;
235 } 326 }
236 327
237 bool UsbDeviceHandle::SetInterfaceAlternateSetting( 328 bool UsbDeviceHandle::SetInterfaceAlternateSetting(
238 const int interface_number, 329 const int interface_number,
239 const int alternate_setting) { 330 const int alternate_setting) {
240 DCHECK(thread_checker_.CalledOnValidThread()); 331 DCHECK(thread_checker_.CalledOnValidThread());
241 if (!handle_) return false; 332 if (!device_) return false;
242 333 if (!ContainsKey(claimed_interfaces_, interface_number)) return false;
243 const int setting_result = libusb_set_interface_alt_setting(handle_, 334 const int rv = libusb_set_interface_alt_setting(handle_,
244 interface_number, alternate_setting); 335 interface_number, alternate_setting);
245 336 if (rv == 0) {
246 return setting_result == 0; 337 claimed_interfaces_[interface_number]->
338 set_alternate_setting(alternate_setting);
339 RefreshEndpointMap();
340 return true;
341 }
342 return false;
247 } 343 }
248 344
249 bool UsbDeviceHandle::ResetDevice() { 345 bool UsbDeviceHandle::ResetDevice() {
250 DCHECK(thread_checker_.CalledOnValidThread()); 346 DCHECK(thread_checker_.CalledOnValidThread());
251 if (!handle_) return false; 347 if (!device_) return false;
252 348
253 return libusb_reset_device(handle_) == 0; 349 return libusb_reset_device(handle_) == 0;
254 } 350 }
255 351
256 bool UsbDeviceHandle::GetSerial(base::string16* serial) { 352 bool UsbDeviceHandle::GetSerial(base::string16* serial) {
257 DCHECK(thread_checker_.CalledOnValidThread()); 353 DCHECK(thread_checker_.CalledOnValidThread());
258 PlatformUsbDevice device = libusb_get_device(handle_); 354 PlatformUsbDevice device = libusb_get_device(handle_);
259 libusb_device_descriptor desc; 355 libusb_device_descriptor desc;
260 356
261 if (libusb_get_device_descriptor(device, &desc) != LIBUSB_SUCCESS) 357 if (libusb_get_device_descriptor(device, &desc) != LIBUSB_SUCCESS)
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 return true; 389 return true;
294 } 390 }
295 return false; 391 return false;
296 } 392 }
297 393
298 void UsbDeviceHandle::ControlTransfer(const UsbEndpointDirection direction, 394 void UsbDeviceHandle::ControlTransfer(const UsbEndpointDirection direction,
299 const TransferRequestType request_type, const TransferRecipient recipient, 395 const TransferRequestType request_type, const TransferRecipient recipient,
300 const uint8 request, const uint16 value, const uint16 index, 396 const uint8 request, const uint16 value, const uint16 index,
301 net::IOBuffer* buffer, const size_t length, const unsigned int timeout, 397 net::IOBuffer* buffer, const size_t length, const unsigned int timeout,
302 const UsbTransferCallback& callback) { 398 const UsbTransferCallback& callback) {
303 if (!handle_) { 399 if (!device_) {
304 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 400 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
305 return; 401 return;
306 } 402 }
307 403
308 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length; 404 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
309 scoped_refptr<net::IOBuffer> resized_buffer(new net::IOBufferWithSize( 405 scoped_refptr<net::IOBuffer> resized_buffer(new net::IOBufferWithSize(
310 resized_length)); 406 resized_length));
311 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(), 407 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
312 length); 408 length);
313 409
314 struct libusb_transfer* const transfer = libusb_alloc_transfer(0); 410 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
315 const uint8 converted_type = CreateRequestType(direction, request_type, 411 const uint8 converted_type = CreateRequestType(direction, request_type,
316 recipient); 412 recipient);
317 libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()), 413 libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()),
318 converted_type, request, value, index, length); 414 converted_type, request, value, index, length);
319 libusb_fill_control_transfer(transfer, handle_, reinterpret_cast<uint8*>( 415 libusb_fill_control_transfer(
320 resized_buffer->data()), HandleTransferCompletion, this, timeout); 416 transfer,
321 SubmitTransfer(transfer, 417 handle_,
418 reinterpret_cast<uint8*>(resized_buffer->data()),
419 PlatformTransferCompletionCallback,
420 this,
421 timeout);
422
423 BrowserThread::PostTask(
424 BrowserThread::FILE,
425 FROM_HERE,
426 base::Bind(&UsbDeviceHandle::SubmitTransfer,
427 this,
428 transfer,
322 USB_TRANSFER_CONTROL, 429 USB_TRANSFER_CONTROL,
323 resized_buffer.get(), 430 resized_buffer,
324 resized_length, 431 resized_length,
325 callback); 432 base::MessageLoopProxy::current(),
433 callback));
326 } 434 }
327 435
328 void UsbDeviceHandle::BulkTransfer(const UsbEndpointDirection direction, 436 void UsbDeviceHandle::BulkTransfer(const UsbEndpointDirection direction,
329 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, 437 const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
330 const unsigned int timeout, const UsbTransferCallback& callback) { 438 const unsigned int timeout, const UsbTransferCallback& callback) {
331 if (!handle_) { 439 if (!device_) {
332 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 440 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
333 return; 441 return;
334 } 442 }
335 443
336 struct libusb_transfer* const transfer = libusb_alloc_transfer(0); 444 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
337 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; 445 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
338 libusb_fill_bulk_transfer(transfer, handle_, new_endpoint, 446 libusb_fill_bulk_transfer(transfer, handle_, new_endpoint,
339 reinterpret_cast<uint8*>(buffer->data()), length, 447 reinterpret_cast<uint8*>(buffer->data()), length,
340 HandleTransferCompletion, this, timeout); 448 PlatformTransferCompletionCallback, this, timeout);
341 SubmitTransfer(transfer, USB_TRANSFER_BULK, buffer, length, callback); 449
450 BrowserThread::PostTask(
451 BrowserThread::FILE,
452 FROM_HERE,
453 base::Bind(&UsbDeviceHandle::SubmitTransfer,
454 this,
455 transfer,
456 USB_TRANSFER_BULK,
457 make_scoped_refptr(buffer),
458 length,
459 base::MessageLoopProxy::current(),
460 callback));
342 } 461 }
343 462
344 void UsbDeviceHandle::InterruptTransfer(const UsbEndpointDirection direction, 463 void UsbDeviceHandle::InterruptTransfer(const UsbEndpointDirection direction,
345 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, 464 const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
346 const unsigned int timeout, const UsbTransferCallback& callback) { 465 const unsigned int timeout, const UsbTransferCallback& callback) {
347 if (!handle_) { 466 if (!device_) {
348 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 467 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
349 return; 468 return;
350 } 469 }
351 470
352 struct libusb_transfer* const transfer = libusb_alloc_transfer(0); 471 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
353 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; 472 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
354 libusb_fill_interrupt_transfer(transfer, handle_, new_endpoint, 473 libusb_fill_interrupt_transfer(transfer, handle_, new_endpoint,
355 reinterpret_cast<uint8*>(buffer->data()), length, 474 reinterpret_cast<uint8*>(buffer->data()), length,
356 HandleTransferCompletion, this, timeout); 475 PlatformTransferCompletionCallback, this, timeout);
357 SubmitTransfer(transfer, USB_TRANSFER_INTERRUPT, buffer, length, callback); 476 BrowserThread::PostTask(
477 BrowserThread::FILE,
478 FROM_HERE,
479 base::Bind(&UsbDeviceHandle::SubmitTransfer,
480 this,
481 transfer,
482 USB_TRANSFER_INTERRUPT,
483 make_scoped_refptr(buffer),
484 length,
485 base::MessageLoopProxy::current(),
486 callback));
358 } 487 }
359 488
360 void UsbDeviceHandle::IsochronousTransfer(const UsbEndpointDirection direction, 489 void UsbDeviceHandle::IsochronousTransfer(const UsbEndpointDirection direction,
361 const uint8 endpoint, net::IOBuffer* buffer, const size_t length, 490 const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
362 const unsigned int packets, const unsigned int packet_length, 491 const unsigned int packets, const unsigned int packet_length,
363 const unsigned int timeout, const UsbTransferCallback& callback) { 492 const unsigned int timeout, const UsbTransferCallback& callback) {
364 if (!handle_) { 493 if (!device_) {
365 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 494 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
366 return; 495 return;
367 } 496 }
368 497
369 const uint64 total_length = packets * packet_length; 498 const uint64 total_length = packets * packet_length;
370 CHECK(packets <= length && total_length <= length) << 499 CHECK(packets <= length && total_length <= length) <<
371 "transfer length is too small"; 500 "transfer length is too small";
372 501
373 struct libusb_transfer* const transfer = libusb_alloc_transfer(packets); 502 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(packets);
374 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; 503 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
375 libusb_fill_iso_transfer(transfer, handle_, new_endpoint, 504 libusb_fill_iso_transfer(transfer, handle_, new_endpoint,
376 reinterpret_cast<uint8*>(buffer->data()), length, packets, 505 reinterpret_cast<uint8*>(buffer->data()), length, packets,
377 HandleTransferCompletion, this, timeout); 506 PlatformTransferCompletionCallback, this, timeout);
378 libusb_set_iso_packet_lengths(transfer, packet_length); 507 libusb_set_iso_packet_lengths(transfer, packet_length);
379 508
380 SubmitTransfer(transfer, USB_TRANSFER_ISOCHRONOUS, buffer, length, callback); 509 BrowserThread::PostTask(
510 BrowserThread::FILE,
511 FROM_HERE,
512 base::Bind(&UsbDeviceHandle::SubmitTransfer,
513 this,
514 transfer,
515 USB_TRANSFER_ISOCHRONOUS,
516 make_scoped_refptr(buffer),
517 length,
518 base::MessageLoopProxy::current(),
519 callback));
381 } 520 }
382 521
383 void UsbDeviceHandle::SubmitTransfer(PlatformUsbTransferHandle handle, 522 void UsbDeviceHandle::RefreshEndpointMap() {
384 UsbTransferType transfer_type, 523 DCHECK(thread_checker_.CalledOnValidThread());
385 net::IOBuffer* buffer, 524 endpoint_map_.clear();
386 const size_t length, 525 for (ClaimedInterfaceMap::iterator it = claimed_interfaces_.begin();
387 const UsbTransferCallback& callback) { 526 it != claimed_interfaces_.end(); ++it) {
527 scoped_refptr<const UsbInterfaceDescriptor> interface_desc =
528 interfaces_->GetInterface(it->first)->GetAltSetting(
529 it->second->alternate_setting());
530 for (size_t i = 0; i < interface_desc->GetNumEndpoints(); i++) {
531 scoped_refptr<const UsbEndpointDescriptor> endpoint =
532 interface_desc->GetEndpoint(i);
533 endpoint_map_[endpoint->GetAddress()] = it->first;
534 }
535 }
536 }
537
538 void UsbDeviceHandle::SubmitTransfer(
539 PlatformUsbTransferHandle handle,
540 UsbTransferType transfer_type,
541 net::IOBuffer* buffer,
542 const size_t length,
543 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
544 const UsbTransferCallback& callback) {
545 DCHECK(thread_checker_.CalledOnValidThread());
546 if (!device_) {
547 message_loop_proxy->PostTask(
548 FROM_HERE,
549 base::Bind(callback, USB_TRANSFER_DISCONNECT,
550 make_scoped_refptr(buffer), 0));
551 }
552
553 unsigned char address = handle->endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK;
554 if (!ContainsKey(endpoint_map_, address)) {
555 // Endpoint for given transfer not found or the interface is not claimed.
556 message_loop_proxy->PostTask(
557 FROM_HERE,
558 base::Bind(callback, USB_TRANSFER_ERROR,
559 make_scoped_refptr(buffer), 0));
560 return;
561 }
562
388 Transfer transfer; 563 Transfer transfer;
389 transfer.transfer_type = transfer_type; 564 transfer.transfer_type = transfer_type;
390 transfer.buffer = buffer; 565 transfer.buffer = buffer;
391 transfer.length = length; 566 transfer.length = length;
392 transfer.callback = callback; 567 transfer.callback = callback;
568 transfer.message_loop_proxy = message_loop_proxy;
569 transfer.claimed_interface = claimed_interfaces_[endpoint_map_[address]];
393 570
394 { 571 if (libusb_submit_transfer(handle) == LIBUSB_SUCCESS) {
395 base::AutoLock lock(lock_);
396 transfers_[handle] = transfer; 572 transfers_[handle] = transfer;
397 } 573 } else {
398 if (libusb_submit_transfer(handle) != LIBUSB_SUCCESS) { 574 message_loop_proxy->PostTask(
399 base::AutoLock lock(lock_); 575 FROM_HERE,
400 transfers_.erase(handle); 576 base::Bind(callback, USB_TRANSFER_ERROR,
401 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 577 make_scoped_refptr(buffer), 0));
402 } 578 }
403 } 579 }
404 580
405 void UsbDeviceHandle::InternalClose() { 581 void UsbDeviceHandle::InternalClose() {
406 DCHECK(thread_checker_.CalledOnValidThread()); 582 DCHECK(thread_checker_.CalledOnValidThread());
407 libusb_close(handle_); 583 if (!device_) return;
408 handle_ = NULL; 584
585 // Cancel all the transfers.
586 for (TransferMap::iterator it = transfers_.begin();
587 it != transfers_.end(); ++it) {
588 // The callback will be called some time later.
589 libusb_cancel_transfer(it->first);
590 }
591
592 // Attempt-release all the interfaces.
593 // It will be retained until the transfer cancellation is finished.
594 claimed_interfaces_.clear();
595
596 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
597 // finish.
409 device_ = NULL; 598 device_ = NULL;
410 } 599 }
OLDNEW
« no previous file with comments | « chrome/browser/usb/usb_device_handle.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698