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