OLD | NEW |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |