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

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

Issue 16316004: Separate usb device handle from usb device. (deprecate) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix the threading mess Created 7 years, 5 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.h ('k') | chrome/browser/usb/usb_device_handle.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/usb/usb_device.h"
6
7 #include <vector>
8
9 #include "base/stl_util.h"
10 #include "base/synchronization/lock.h"
11 #include "chrome/browser/usb/usb_interface.h"
12 #include "chrome/browser/usb/usb_service.h"
13 #include "third_party/libusb/src/libusb/libusb.h"
14
15 namespace {
16
17 static uint8 ConvertTransferDirection(
18 const UsbEndpointDirection direction) {
19 switch (direction) {
20 case USB_DIRECTION_INBOUND:
21 return LIBUSB_ENDPOINT_IN;
22 case USB_DIRECTION_OUTBOUND:
23 return LIBUSB_ENDPOINT_OUT;
24 default:
25 NOTREACHED();
26 return LIBUSB_ENDPOINT_IN;
27 }
28 }
29
30 static uint8 CreateRequestType(const UsbEndpointDirection direction,
31 const UsbDevice::TransferRequestType request_type,
32 const UsbDevice::TransferRecipient recipient) {
33 uint8 result = ConvertTransferDirection(direction);
34
35 switch (request_type) {
36 case UsbDevice::STANDARD:
37 result |= LIBUSB_REQUEST_TYPE_STANDARD;
38 break;
39 case UsbDevice::CLASS:
40 result |= LIBUSB_REQUEST_TYPE_CLASS;
41 break;
42 case UsbDevice::VENDOR:
43 result |= LIBUSB_REQUEST_TYPE_VENDOR;
44 break;
45 case UsbDevice::RESERVED:
46 result |= LIBUSB_REQUEST_TYPE_RESERVED;
47 break;
48 }
49
50 switch (recipient) {
51 case UsbDevice::DEVICE:
52 result |= LIBUSB_RECIPIENT_DEVICE;
53 break;
54 case UsbDevice::INTERFACE:
55 result |= LIBUSB_RECIPIENT_INTERFACE;
56 break;
57 case UsbDevice::ENDPOINT:
58 result |= LIBUSB_RECIPIENT_ENDPOINT;
59 break;
60 case UsbDevice::OTHER:
61 result |= LIBUSB_RECIPIENT_OTHER;
62 break;
63 }
64
65 return result;
66 }
67
68 static UsbTransferStatus ConvertTransferStatus(
69 const libusb_transfer_status status) {
70 switch (status) {
71 case LIBUSB_TRANSFER_COMPLETED:
72 return USB_TRANSFER_COMPLETED;
73 case LIBUSB_TRANSFER_ERROR:
74 return USB_TRANSFER_ERROR;
75 case LIBUSB_TRANSFER_TIMED_OUT:
76 return USB_TRANSFER_TIMEOUT;
77 case LIBUSB_TRANSFER_STALL:
78 return USB_TRANSFER_STALLED;
79 case LIBUSB_TRANSFER_NO_DEVICE:
80 return USB_TRANSFER_DISCONNECT;
81 case LIBUSB_TRANSFER_OVERFLOW:
82 return USB_TRANSFER_OVERFLOW;
83 case LIBUSB_TRANSFER_CANCELLED:
84 return USB_TRANSFER_CANCELLED;
85 default:
86 NOTREACHED();
87 return USB_TRANSFER_ERROR;
88 }
89 }
90
91 static void LIBUSB_CALL HandleTransferCompletion(
92 struct libusb_transfer* transfer) {
93 UsbDevice* const device = reinterpret_cast<UsbDevice*>(transfer->user_data);
94 device->TransferComplete(transfer);
95 }
96
97 } // namespace
98
99 UsbDevice::Transfer::Transfer() : length(0) {}
100
101 UsbDevice::Transfer::~Transfer() {}
102
103 UsbDevice::UsbDevice(UsbService* service, PlatformUsbDeviceHandle handle)
104 : service_(service), handle_(handle) {
105 DCHECK(handle) << "Cannot create device with NULL handle.";
106 }
107
108 UsbDevice::UsbDevice() : service_(NULL), handle_(NULL) {}
109
110 UsbDevice::~UsbDevice() {}
111
112 void UsbDevice::Close(const base::Callback<void()>& callback) {
113 CheckDevice();
114 service_->CloseDevice(this);
115 handle_ = NULL;
116 callback.Run();
117 }
118
119 void UsbDevice::TransferComplete(PlatformUsbTransferHandle handle) {
120 base::AutoLock lock(lock_);
121
122 // TODO(gdk): Handle device disconnect.
123 DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed";
124 Transfer* const transfer = &transfers_[handle];
125
126 DCHECK(handle->actual_length >= 0) << "Negative actual length received";
127 size_t actual_length =
128 static_cast<size_t>(std::max(handle->actual_length, 0));
129
130 DCHECK(transfer->length >= actual_length) <<
131 "data too big for our buffer (libusb failure?)";
132
133 scoped_refptr<net::IOBuffer> buffer = transfer->buffer;
134 switch (transfer->transfer_type) {
135 case USB_TRANSFER_CONTROL:
136 // If the transfer is a control transfer we do not expose the control
137 // setup header to the caller. This logic strips off the header if
138 // present before invoking the callback provided with the transfer.
139 if (actual_length > 0) {
140 CHECK(transfer->length >= LIBUSB_CONTROL_SETUP_SIZE) <<
141 "buffer was not correctly set: too small for the control header";
142
143 if (transfer->length >= actual_length &&
144 actual_length >= LIBUSB_CONTROL_SETUP_SIZE) {
145 // If the payload is zero bytes long, pad out the allocated buffer
146 // size to one byte so that an IOBuffer of that size can be allocated.
147 scoped_refptr<net::IOBuffer> resized_buffer = new net::IOBuffer(
148 std::max(actual_length, static_cast<size_t>(1)));
149 memcpy(resized_buffer->data(),
150 buffer->data() + LIBUSB_CONTROL_SETUP_SIZE,
151 actual_length);
152 buffer = resized_buffer;
153 }
154 }
155 break;
156
157 case USB_TRANSFER_ISOCHRONOUS:
158 // Isochronous replies might carry data in the different isoc packets even
159 // if the transfer actual_data value is zero. Furthermore, not all of the
160 // received packets might contain data, so we need to calculate how many
161 // data bytes we are effectively providing and pack the results.
162 if (actual_length == 0) {
163 size_t packet_buffer_start = 0;
164 for (int i = 0; i < handle->num_iso_packets; ++i) {
165 PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i];
166 if (packet->actual_length > 0) {
167 // We don't need to copy as long as all packets until now provide
168 // all the data the packet can hold.
169 if (actual_length < packet_buffer_start) {
170 CHECK(packet_buffer_start + packet->actual_length <=
171 transfer->length);
172 memmove(buffer->data() + actual_length,
173 buffer->data() + packet_buffer_start,
174 packet->actual_length);
175 }
176 actual_length += packet->actual_length;
177 }
178
179 packet_buffer_start += packet->length;
180 }
181 }
182 break;
183
184 case USB_TRANSFER_BULK:
185 case USB_TRANSFER_INTERRUPT:
186 break;
187
188 default:
189 NOTREACHED() << "Invalid usb transfer type";
190 }
191
192 transfer->callback.Run(ConvertTransferStatus(handle->status), buffer,
193 actual_length);
194
195 transfers_.erase(handle);
196 libusb_free_transfer(handle);
197 }
198
199 void UsbDevice::ListInterfaces(UsbConfigDescriptor* config,
200 const UsbInterfaceCallback& callback) {
201 CheckDevice();
202
203 PlatformUsbDevice device = libusb_get_device(handle_);
204
205 PlatformUsbConfigDescriptor platform_config;
206 const int list_result = libusb_get_active_config_descriptor(device,
207 &platform_config);
208 if (list_result == 0) {
209 config->Reset(platform_config);
210 }
211 callback.Run(list_result == 0);
212 }
213
214 void UsbDevice::ClaimInterface(const int interface_number,
215 const UsbInterfaceCallback& callback) {
216 CheckDevice();
217
218 const int claim_result = libusb_claim_interface(handle_, interface_number);
219 callback.Run(claim_result == 0);
220 }
221
222 void UsbDevice::ReleaseInterface(const int interface_number,
223 const UsbInterfaceCallback& callback) {
224 CheckDevice();
225
226 const int release_result = libusb_release_interface(handle_,
227 interface_number);
228 callback.Run(release_result == 0);
229 }
230
231 void UsbDevice::SetInterfaceAlternateSetting(
232 const int interface_number,
233 const int alternate_setting,
234 const UsbInterfaceCallback& callback) {
235 CheckDevice();
236
237 const int setting_result = libusb_set_interface_alt_setting(handle_,
238 interface_number, alternate_setting);
239
240 callback.Run(setting_result == 0);
241 }
242
243 void UsbDevice::ControlTransfer(const UsbEndpointDirection direction,
244 const TransferRequestType request_type, const TransferRecipient recipient,
245 const uint8 request, const uint16 value, const uint16 index,
246 net::IOBuffer* buffer, const size_t length, const unsigned int timeout,
247 const UsbTransferCallback& callback) {
248 CheckDevice();
249
250 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
251 scoped_refptr<net::IOBuffer> resized_buffer(new net::IOBufferWithSize(
252 resized_length));
253 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
254 length);
255
256 struct libusb_transfer* const transfer = libusb_alloc_transfer(0);
257 const uint8 converted_type = CreateRequestType(direction, request_type,
258 recipient);
259 libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()),
260 converted_type, request, value, index, length);
261 libusb_fill_control_transfer(transfer, handle_, reinterpret_cast<uint8*>(
262 resized_buffer->data()), HandleTransferCompletion, this, timeout);
263 SubmitTransfer(transfer,
264 USB_TRANSFER_CONTROL,
265 resized_buffer.get(),
266 resized_length,
267 callback);
268 }
269
270 void UsbDevice::BulkTransfer(const UsbEndpointDirection direction,
271 const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
272 const unsigned int timeout, const UsbTransferCallback& callback) {
273 CheckDevice();
274
275 struct libusb_transfer* const transfer = libusb_alloc_transfer(0);
276 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
277 libusb_fill_bulk_transfer(transfer, handle_, new_endpoint,
278 reinterpret_cast<uint8*>(buffer->data()), length,
279 HandleTransferCompletion, this, timeout);
280 SubmitTransfer(transfer, USB_TRANSFER_BULK, buffer, length, callback);
281 }
282
283 void UsbDevice::InterruptTransfer(const UsbEndpointDirection direction,
284 const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
285 const unsigned int timeout, const UsbTransferCallback& callback) {
286 CheckDevice();
287
288 struct libusb_transfer* const transfer = libusb_alloc_transfer(0);
289 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
290 libusb_fill_interrupt_transfer(transfer, handle_, new_endpoint,
291 reinterpret_cast<uint8*>(buffer->data()), length,
292 HandleTransferCompletion, this, timeout);
293 SubmitTransfer(transfer, USB_TRANSFER_INTERRUPT, buffer, length, callback);
294 }
295
296 void UsbDevice::IsochronousTransfer(const UsbEndpointDirection direction,
297 const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
298 const unsigned int packets, const unsigned int packet_length,
299 const unsigned int timeout, const UsbTransferCallback& callback) {
300 CheckDevice();
301
302 const uint64 total_length = packets * packet_length;
303 CHECK(packets <= length && total_length <= length) <<
304 "transfer length is too small";
305
306 struct libusb_transfer* const transfer = libusb_alloc_transfer(packets);
307 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
308 libusb_fill_iso_transfer(transfer, handle_, new_endpoint,
309 reinterpret_cast<uint8*>(buffer->data()), length, packets,
310 HandleTransferCompletion, this, timeout);
311 libusb_set_iso_packet_lengths(transfer, packet_length);
312
313 SubmitTransfer(transfer, USB_TRANSFER_ISOCHRONOUS, buffer, length, callback);
314 }
315
316 void UsbDevice::ResetDevice(const base::Callback<void(bool)>& callback) {
317 CheckDevice();
318 callback.Run(libusb_reset_device(handle_) == 0);
319 }
320
321 void UsbDevice::CheckDevice() {
322 DCHECK(handle_) << "Device is already closed.";
323 }
324
325 void UsbDevice::SubmitTransfer(PlatformUsbTransferHandle handle,
326 UsbTransferType transfer_type,
327 net::IOBuffer* buffer,
328 const size_t length,
329 const UsbTransferCallback& callback) {
330 Transfer transfer;
331 transfer.transfer_type = transfer_type;
332 transfer.buffer = buffer;
333 transfer.length = length;
334 transfer.callback = callback;
335
336 {
337 base::AutoLock lock(lock_);
338 transfers_[handle] = transfer;
339 libusb_submit_transfer(handle);
340 }
341 }
OLDNEW
« no previous file with comments | « chrome/browser/usb/usb_device.h ('k') | chrome/browser/usb/usb_device_handle.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698