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

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