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

Side by Side Diff: content/renderer/usb/web_usb_device_impl.cc

Issue 1314493003: Implement most of WebUSB device client interface (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: allow null data on controlTransfer Created 5 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "content/renderer/usb/web_usb_device_impl.h" 5 #include "content/renderer/usb/web_usb_device_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
10 #include "content/child/scoped_web_callbacks.h"
10 #include "content/renderer/usb/type_converters.h" 11 #include "content/renderer/usb/type_converters.h"
11 #include "device/devices_app/public/cpp/constants.h" 12 #include "device/devices_app/public/cpp/constants.h"
12 #include "mojo/application/public/cpp/connect.h" 13 #include "mojo/application/public/cpp/connect.h"
13 #include "mojo/application/public/interfaces/shell.mojom.h" 14 #include "mojo/application/public/interfaces/shell.mojom.h"
14 #include "third_party/WebKit/public/platform/WebVector.h" 15 #include "third_party/WebKit/public/platform/WebVector.h"
15 #include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceInfo.h" 16 #include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceInfo.h"
16 #include "third_party/WebKit/public/platform/modules/webusb/WebUSBTransferInfo.h " 17 #include "third_party/WebKit/public/platform/modules/webusb/WebUSBTransferInfo.h "
17 18
18 namespace content { 19 namespace content {
19 20
20 namespace { 21 namespace {
21 22
23 const char kClaimInterfaceFailed[] = "Unable to claim interface.";
24 const char kClearHaltFailed[] = "Unable to clear endpoint.";
25 const char kDeviceNoAccess[] = "Access denied.";
26 const char kDeviceNotFound[] = "Device not found.";
27 const char kDeviceNotOpened[] = "Device not opened.";
28 const char kDeviceUnavailable[] = "Device unavailable.";
29 const char kDeviceResetFailed[] = "Unable to reset the device.";
22 const char kNotImplementedError[] = "Not implemented."; 30 const char kNotImplementedError[] = "Not implemented.";
31 const char kReleaseInterfaceFailed[] = "Unable to release interface.";
32 const char kSetConfigurationFailed[] = "Unable to set device configuration.";
33 const char kSetInterfaceFailed[] = "Unable to set device interface.";
34 const char kTransferFailed[] = "Transfer failed.";
23 35
24 template <typename ResultType> 36 // Generic default rejection handler for any WebUSB callbacks type. Assumes
25 void RejectAsNotImplemented( 37 // |CallbacksType| is a blink::WebCallbacks<T, const blink::WebUSBError&>
26 blink::WebCallbacks<ResultType, const blink::WebUSBError&>* callbacks) { 38 // for any type |T|.
27 callbacks->onError( 39 template <typename CallbacksType>
28 blink::WebUSBError(blink::WebUSBError::Error::Service, 40 void RejectWithError(const blink::WebUSBError& error,
29 base::UTF8ToUTF16(kNotImplementedError))); 41 scoped_ptr<CallbacksType> callbacks) {
30 delete callbacks; 42 callbacks->onError(error);
43 }
44
45 template <typename CallbacksType>
46 void RejectWithDeviceError(const std::string& message,
47 scoped_ptr<CallbacksType> callbacks) {
48 RejectWithError(blink::WebUSBError(blink::WebUSBError::Error::Device,
49 base::UTF8ToUTF16(message)),
50 callbacks.Pass());
51 }
52
53 template <typename CallbacksType>
54 void RejectWithTransferError(scoped_ptr<CallbacksType> callbacks) {
55 RejectWithError(blink::WebUSBError(blink::WebUSBError::Error::Transfer,
56 base::UTF8ToUTF16(kTransferFailed)),
57 callbacks.Pass());
58 }
59
60 // Create a new ScopedWebCallbacks for WebUSB device callbacks, defaulting to
61 // a "device unavailable" rejection.
62 template <typename CallbacksType>
63 ScopedWebCallbacks<CallbacksType> MakeScopedUSBCallbacks(
64 CallbacksType* callbacks) {
65 return make_scoped_web_callbacks(
66 callbacks,
67 base::Bind(&RejectWithError<CallbacksType>,
68 blink::WebUSBError(blink::WebUSBError::Error::Device,
69 base::UTF8ToUTF16(kDeviceUnavailable))));
70 }
71
72 void OnOpenDevice(
73 ScopedWebCallbacks<blink::WebUSBDeviceOpenCallbacks> callbacks,
74 device::usb::OpenDeviceError error) {
75 auto scoped_callbacks = callbacks.PassCallbacks();
76 switch(error) {
77 case device::usb::OPEN_DEVICE_ERROR_OK:
78 scoped_callbacks->onSuccess();
79 break;
80 case device::usb::OPEN_DEVICE_ERROR_NOT_FOUND:
81 scoped_callbacks->onError(blink::WebUSBError(
82 blink::WebUSBError::Error::Device,
83 base::UTF8ToUTF16(kDeviceNotFound)));
84 break;
85 case device::usb::OPEN_DEVICE_ERROR_ACCESS_DENIED:
86 scoped_callbacks->onError(blink::WebUSBError(
87 blink::WebUSBError::Error::Device,
88 base::UTF8ToUTF16(kDeviceNoAccess)));
89 break;
90 default:
91 NOTREACHED();
92 }
93 }
94
95 void OnDeviceClosed(
96 ScopedWebCallbacks<blink::WebUSBDeviceCloseCallbacks> callbacks) {
97 callbacks.PassCallbacks()->onSuccess();
98 }
99
100 void HandlePassFailDeviceOperation(
101 ScopedWebCallbacks<blink::WebCallbacks<void, const blink::WebUSBError&>>
102 callbacks,
103 const std::string& failure_message,
104 bool success) {
105 auto scoped_callbacks = callbacks.PassCallbacks();
106 if (success)
107 scoped_callbacks->onSuccess();
108 else
109 RejectWithDeviceError(failure_message, scoped_callbacks.Pass());
110 }
111
112 void OnTransferIn(
113 ScopedWebCallbacks<blink::WebUSBDeviceControlTransferCallbacks> callbacks,
114 device::usb::TransferStatus status,
115 mojo::Array<uint8_t> data) {
116 auto scoped_callbacks = callbacks.PassCallbacks();
117 if (status != device::usb::TRANSFER_STATUS_COMPLETED) {
118 RejectWithTransferError(scoped_callbacks.Pass());
119 return;
120 }
121 scoped_ptr<blink::WebUSBTransferInfo> info(new blink::WebUSBTransferInfo());
122 info->status = blink::WebUSBTransferInfo::Status::Ok;
123 info->data.assign(data);
124 scoped_callbacks->onSuccess(adoptWebPtr(info.release()));
125 }
126
127 void OnTransferOut(
128 ScopedWebCallbacks<blink::WebUSBDeviceControlTransferCallbacks> callbacks,
129 size_t bytes_written,
130 device::usb::TransferStatus status) {
131 auto scoped_callbacks = callbacks.PassCallbacks();
132 scoped_ptr<blink::WebUSBTransferInfo> info(new blink::WebUSBTransferInfo());
133 switch (status) {
134 case device::usb::TRANSFER_STATUS_COMPLETED:
135 info->status = blink::WebUSBTransferInfo::Status::Ok;
136 break;
137 case device::usb::TRANSFER_STATUS_STALLED:
138 info->status = blink::WebUSBTransferInfo::Status::Stall;
139 break;
140 case device::usb::TRANSFER_STATUS_BABBLE:
141 info->status = blink::WebUSBTransferInfo::Status::Babble;
142 break;
143 default:
144 RejectWithTransferError(scoped_callbacks.Pass());
145 return;
146 }
147
148 // TODO(rockot): Device::ControlTransferOut should expose the number of bytes
149 // actually transferred so we can send it from here.
150 info->bytesWritten = bytes_written;
151 scoped_callbacks->onSuccess(adoptWebPtr(info.release()));
31 } 152 }
32 153
33 } // namespace 154 } // namespace
34 155
35 WebUSBDeviceImpl::WebUSBDeviceImpl(device::usb::DeviceManagerPtr device_manager, 156 WebUSBDeviceImpl::WebUSBDeviceImpl(device::usb::DeviceManagerPtr device_manager,
36 const blink::WebUSBDeviceInfo& device_info) 157 const blink::WebUSBDeviceInfo& device_info)
37 : device_manager_(device_manager.Pass()), 158 : device_manager_(device_manager.Pass()),
38 device_info_(device_info), 159 device_info_(device_info),
39 weak_factory_(this) {} 160 weak_factory_(this) {}
40 161
41 WebUSBDeviceImpl::~WebUSBDeviceImpl() {} 162 WebUSBDeviceImpl::~WebUSBDeviceImpl() {}
42 163
43 const blink::WebUSBDeviceInfo& WebUSBDeviceImpl::info() const { 164 const blink::WebUSBDeviceInfo& WebUSBDeviceImpl::info() const {
44 return device_info_; 165 return device_info_;
45 } 166 }
46 167
47 void WebUSBDeviceImpl::open(blink::WebUSBDeviceOpenCallbacks* callbacks) { 168 void WebUSBDeviceImpl::open(blink::WebUSBDeviceOpenCallbacks* callbacks) {
48 RejectAsNotImplemented(callbacks); 169 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
170 device_manager_->OpenDevice(
171 device_info_.guid.utf8(),
172 mojo::GetProxy(&device_),
173 base::Bind(&OnOpenDevice, base::Passed(&scoped_callbacks)));
49 } 174 }
50 175
51 void WebUSBDeviceImpl::close(blink::WebUSBDeviceCloseCallbacks* callbacks) { 176 void WebUSBDeviceImpl::close(blink::WebUSBDeviceCloseCallbacks* callbacks) {
52 RejectAsNotImplemented(callbacks); 177 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
178 if (!device_) {
179 RejectWithDeviceError(kDeviceNotOpened, scoped_callbacks.PassCallbacks());
180 } else {
181 device_->Close(
182 base::Bind(&OnDeviceClosed, base::Passed(&scoped_callbacks)));
183 }
53 } 184 }
54 185
55 void WebUSBDeviceImpl::setConfiguration( 186 void WebUSBDeviceImpl::setConfiguration(
56 uint8_t configuration_value, 187 uint8_t configuration_value,
57 blink::WebUSBDeviceSetConfigurationCallbacks* callbacks) { 188 blink::WebUSBDeviceSetConfigurationCallbacks* callbacks) {
58 RejectAsNotImplemented(callbacks); 189 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
190 if (!device_) {
191 RejectWithDeviceError(kDeviceNotOpened, scoped_callbacks.PassCallbacks());
192 } else {
193 device_->SetConfiguration(
194 configuration_value,
195 base::Bind(&HandlePassFailDeviceOperation,
196 base::Passed(&scoped_callbacks), kSetConfigurationFailed));
197 }
59 } 198 }
60 199
61 void WebUSBDeviceImpl::claimInterface( 200 void WebUSBDeviceImpl::claimInterface(
62 uint8_t interface_number, 201 uint8_t interface_number,
63 blink::WebUSBDeviceClaimInterfaceCallbacks* callbacks) { 202 blink::WebUSBDeviceClaimInterfaceCallbacks* callbacks) {
64 RejectAsNotImplemented(callbacks); 203 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
204 if (!device_) {
205 RejectWithDeviceError(kDeviceNotOpened, scoped_callbacks.PassCallbacks());
206 } else {
207 device_->ClaimInterface(
208 interface_number,
209 base::Bind(&HandlePassFailDeviceOperation,
210 base::Passed(&scoped_callbacks), kClaimInterfaceFailed));
211 }
65 } 212 }
66 213
67 void WebUSBDeviceImpl::releaseInterface( 214 void WebUSBDeviceImpl::releaseInterface(
68 uint8_t interface_number, 215 uint8_t interface_number,
69 blink::WebUSBDeviceReleaseInterfaceCallbacks* callbacks) { 216 blink::WebUSBDeviceReleaseInterfaceCallbacks* callbacks) {
70 RejectAsNotImplemented(callbacks); 217 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
218 if (!device_) {
219 RejectWithDeviceError(kDeviceNotOpened, scoped_callbacks.PassCallbacks());
220 } else {
221 device_->ReleaseInterface(
222 interface_number,
223 base::Bind(&HandlePassFailDeviceOperation,
224 base::Passed(&scoped_callbacks), kReleaseInterfaceFailed));
225 }
71 } 226 }
72 227
73 void WebUSBDeviceImpl::setInterface( 228 void WebUSBDeviceImpl::setInterface(
74 uint8_t interface_number, 229 uint8_t interface_number,
75 uint8_t alternate_setting, 230 uint8_t alternate_setting,
76 blink::WebUSBDeviceSetInterfaceAlternateSettingCallbacks* callbacks) { 231 blink::WebUSBDeviceSetInterfaceAlternateSettingCallbacks* callbacks) {
77 RejectAsNotImplemented(callbacks); 232 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
233 if (!device_) {
234 RejectWithDeviceError(kDeviceNotOpened, scoped_callbacks.PassCallbacks());
235 } else {
236 device_->SetInterfaceAlternateSetting(
237 interface_number, alternate_setting,
238 base::Bind(&HandlePassFailDeviceOperation,
239 base::Passed(&scoped_callbacks), kSetInterfaceFailed));
240 }
78 } 241 }
79 242
80 void WebUSBDeviceImpl::clearHalt( 243 void WebUSBDeviceImpl::clearHalt(
81 uint8_t endpoint_number, 244 uint8_t endpoint_number,
82 blink::WebUSBDeviceClearHaltCallbacks* callbacks) { 245 blink::WebUSBDeviceClearHaltCallbacks* callbacks) {
83 RejectAsNotImplemented(callbacks); 246 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
247 if (!device_) {
248 RejectWithDeviceError(kDeviceNotOpened, scoped_callbacks.PassCallbacks());
249 } else {
250 device_->ClearHalt(
251 endpoint_number,
252 base::Bind(&HandlePassFailDeviceOperation,
253 base::Passed(&scoped_callbacks), kClearHaltFailed));
254 }
84 } 255 }
85 256
86 void WebUSBDeviceImpl::controlTransfer( 257 void WebUSBDeviceImpl::controlTransfer(
87 const blink::WebUSBDevice::ControlTransferParameters& parameters, 258 const blink::WebUSBDevice::ControlTransferParameters& parameters,
88 uint8_t* data, 259 uint8_t* data,
89 size_t data_size, 260 size_t data_size,
90 unsigned int timeout, 261 unsigned int timeout,
91 blink::WebUSBDeviceControlTransferCallbacks* callbacks) { 262 blink::WebUSBDeviceControlTransferCallbacks* callbacks) {
92 RejectAsNotImplemented(callbacks); 263 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
264 if (!device_) {
265 RejectWithDeviceError(kDeviceNotOpened, scoped_callbacks.PassCallbacks());
266 } else {
267 device::usb::ControlTransferParamsPtr params =
268 device::usb::ControlTransferParams::From(parameters);
269 switch (parameters.direction) {
270 case WebUSBDevice::TransferDirection::In:
271 device_->ControlTransferIn(params.Pass(), data_size, timeout,
272 base::Bind(&OnTransferIn, base::Passed(&scoped_callbacks)));
273 break;
274 case WebUSBDevice::TransferDirection::Out: {
275 std::vector<uint8_t> bytes;
276 if (data)
277 bytes.assign(data, data + data_size);
278 mojo::Array<uint8_t> mojo_bytes;
279 mojo_bytes.Swap(&bytes);
280 device_->ControlTransferOut(params.Pass(), mojo_bytes.Pass(), timeout,
281 base::Bind(&OnTransferOut, base::Passed(&scoped_callbacks),
282 data_size));
283 break;
284 }
285 default:
286 NOTREACHED();
287 }
288 }
93 } 289 }
94 290
95 void WebUSBDeviceImpl::transfer( 291 void WebUSBDeviceImpl::transfer(
96 blink::WebUSBDevice::TransferDirection direction, 292 blink::WebUSBDevice::TransferDirection direction,
97 uint8_t endpoint_number, 293 uint8_t endpoint_number,
98 uint8_t* data, 294 uint8_t* data,
99 size_t data_size, 295 size_t data_size,
100 unsigned int timeout, 296 unsigned int timeout,
101 blink::WebUSBDeviceBulkTransferCallbacks* callbacks) { 297 blink::WebUSBDeviceBulkTransferCallbacks* callbacks) {
102 RejectAsNotImplemented(callbacks); 298 RejectWithDeviceError(kNotImplementedError, make_scoped_ptr(callbacks));
103 } 299 }
104 300
105 void WebUSBDeviceImpl::reset(blink::WebUSBDeviceResetCallbacks* callbacks) { 301 void WebUSBDeviceImpl::reset(blink::WebUSBDeviceResetCallbacks* callbacks) {
106 RejectAsNotImplemented(callbacks); 302 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
303 if (!device_) {
304 RejectWithDeviceError(kDeviceNotOpened, scoped_callbacks.PassCallbacks());
305 } else {
306 device_->Reset(
307 base::Bind(&HandlePassFailDeviceOperation,
308 base::Passed(&scoped_callbacks), kDeviceResetFailed));
309 }
107 } 310 }
108 311
109 } // namespace content 312 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698