1 // Copyright 2014 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.
5 #include "extensions/browser/api/hid/hid_api.h"
10 #include "device/hid/hid_connection.h"
11 #include "device/hid/hid_device_info.h"
12 #include "device/hid/hid_service.h"
13 #include "extensions/browser/api/api_resource_manager.h"
14 #include "extensions/browser/api/extensions_api_client.h"
15 #include "extensions/common/api/hid.h"
16 #include "extensions/common/permissions/permissions_data.h"
17 #include "extensions/common/permissions/usb_device_permission.h"
18 #include "net/base/io_buffer.h"
20 namespace hid = extensions::core_api::hid;
22 using device::HidConnection;
23 using device::HidDeviceInfo;
24 using device::HidService;
28 const char kErrorPermissionDenied[] = "Permission to access device was denied.";
29 const char kErrorInvalidDeviceId[] = "Invalid HID device ID.";
30 const char kErrorFailedToOpenDevice[] = "Failed to open HID device.";
31 const char kErrorConnectionNotFound[] = "Connection not established.";
32 const char kErrorTransfer[] = "Transfer failed.";
34 base::Value* PopulateHidConnection(int connection_id,
35 scoped_refptr<HidConnection> connection) {
36 hid::HidConnectInfo connection_value;
37 connection_value.connection_id = connection_id;
38 return connection_value.ToValue().release();
43 namespace extensions {
45 HidAsyncApiFunction::HidAsyncApiFunction()
46 : device_manager_(NULL), connection_manager_(NULL) {}
48 HidAsyncApiFunction::~HidAsyncApiFunction() {}
50 bool HidAsyncApiFunction::PrePrepare() {
51 device_manager_ = HidDeviceManager::Get(browser_context());
52 DCHECK(device_manager_);
54 ApiResourceManager<HidConnectionResource>::Get(browser_context());
55 DCHECK(connection_manager_);
56 set_work_thread_id(content::BrowserThread::FILE);
60 bool HidAsyncApiFunction::Respond() { return error_.empty(); }
62 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource(
63 int api_resource_id) {
64 return connection_manager_->Get(extension_->id(), api_resource_id);
67 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) {
68 connection_manager_->Remove(extension_->id(), api_resource_id);
71 void HidAsyncApiFunction::CompleteWithError(const std::string& error) {
76 HidGetDevicesFunction::HidGetDevicesFunction() {}
78 HidGetDevicesFunction::~HidGetDevicesFunction() {}
80 bool HidGetDevicesFunction::Prepare() {
81 parameters_ = hid::GetDevices::Params::Create(*args_);
82 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
86 void HidGetDevicesFunction::AsyncWorkStart() {
87 const uint16_t vendor_id = parameters_->options.vendor_id;
88 const uint16_t product_id = parameters_->options.product_id;
89 UsbDevicePermission::CheckParam param(
90 vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
91 if (!extension()->permissions_data()->CheckAPIPermissionWithParam(
92 APIPermission::kUsbDevice, ¶m)) {
93 LOG(WARNING) << "Insufficient permissions to access device.";
94 CompleteWithError(kErrorPermissionDenied);
98 SetResult(device_manager_->GetApiDevices(vendor_id, product_id).release());
102 HidConnectFunction::HidConnectFunction() {}
104 HidConnectFunction::~HidConnectFunction() {}
106 bool HidConnectFunction::Prepare() {
107 parameters_ = hid::Connect::Params::Create(*args_);
108 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
112 void HidConnectFunction::AsyncWorkStart() {
113 device::HidDeviceInfo device_info;
114 if (!device_manager_->GetDeviceInfo(parameters_->device_id, &device_info)) {
115 CompleteWithError(kErrorInvalidDeviceId);
119 UsbDevicePermission::CheckParam param(
120 device_info.vendor_id,
121 device_info.product_id,
122 UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
123 if (!extension()->permissions_data()->CheckAPIPermissionWithParam(
124 APIPermission::kUsbDevice, ¶m)) {
125 LOG(WARNING) << "Insufficient permissions to access device.";
126 CompleteWithError(kErrorPermissionDenied);
130 HidService* hid_service = ExtensionsAPIClient::Get()->GetHidService();
132 scoped_refptr<HidConnection> connection =
133 hid_service->Connect(device_info.device_id);
135 CompleteWithError(kErrorFailedToOpenDevice);
138 int connection_id = connection_manager_->Add(
139 new HidConnectionResource(extension_->id(), connection));
140 SetResult(PopulateHidConnection(connection_id, connection));
141 AsyncWorkCompleted();
144 HidDisconnectFunction::HidDisconnectFunction() {}
146 HidDisconnectFunction::~HidDisconnectFunction() {}
148 bool HidDisconnectFunction::Prepare() {
149 parameters_ = hid::Disconnect::Params::Create(*args_);
150 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
154 void HidDisconnectFunction::AsyncWorkStart() {
155 int connection_id = parameters_->connection_id;
156 HidConnectionResource* resource =
157 connection_manager_->Get(extension_->id(), connection_id);
159 CompleteWithError(kErrorConnectionNotFound);
162 connection_manager_->Remove(extension_->id(), connection_id);
163 AsyncWorkCompleted();
166 HidReceiveFunction::HidReceiveFunction() {}
168 HidReceiveFunction::~HidReceiveFunction() {}
170 bool HidReceiveFunction::Prepare() {
171 parameters_ = hid::Receive::Params::Create(*args_);
172 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
176 void HidReceiveFunction::AsyncWorkStart() {
177 int connection_id = parameters_->connection_id;
178 HidConnectionResource* resource =
179 connection_manager_->Get(extension_->id(), connection_id);
181 CompleteWithError(kErrorConnectionNotFound);
185 scoped_refptr<device::HidConnection> connection = resource->connection();
186 has_report_id_ = connection->device_info().has_report_id;
187 int size = connection->device_info().max_input_report_size;
188 if (has_report_id_) {
189 ++size; // One byte at the beginning of the buffer for the report ID.
191 buffer_ = new net::IOBufferWithSize(size);
192 connection->Read(buffer_, base::Bind(&HidReceiveFunction::OnFinished, this));
195 void HidReceiveFunction::OnFinished(bool success, size_t bytes) {
197 CompleteWithError(kErrorTransfer);
202 const char* data = buffer_->data();
203 if (has_report_id_) {
205 CompleteWithError(kErrorTransfer);
213 scoped_ptr<base::ListValue> result(new base::ListValue());
214 result->Append(new base::FundamentalValue(report_id));
215 result->Append(base::BinaryValue::CreateWithCopiedBuffer(data, bytes));
216 SetResultList(result.Pass());
217 AsyncWorkCompleted();
220 HidSendFunction::HidSendFunction() {}
222 HidSendFunction::~HidSendFunction() {}
224 bool HidSendFunction::Prepare() {
225 parameters_ = hid::Send::Params::Create(*args_);
226 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
230 void HidSendFunction::AsyncWorkStart() {
231 int connection_id = parameters_->connection_id;
232 HidConnectionResource* resource =
233 connection_manager_->Get(extension_->id(), connection_id);
235 CompleteWithError(kErrorConnectionNotFound);
239 scoped_refptr<net::IOBufferWithSize> buffer(
240 new net::IOBufferWithSize(parameters_->data.size()));
241 memcpy(buffer->data(), parameters_->data.c_str(), parameters_->data.size());
242 resource->connection()->Write(static_cast<uint8_t>(parameters_->report_id),
244 base::Bind(&HidSendFunction::OnFinished, this));
247 void HidSendFunction::OnFinished(bool success, size_t bytes) {
249 CompleteWithError(kErrorTransfer);
252 AsyncWorkCompleted();
255 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
257 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
259 bool HidReceiveFeatureReportFunction::Prepare() {
260 parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
261 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
265 void HidReceiveFeatureReportFunction::AsyncWorkStart() {
266 int connection_id = parameters_->connection_id;
267 HidConnectionResource* resource =
268 connection_manager_->Get(extension_->id(), connection_id);
270 CompleteWithError(kErrorConnectionNotFound);
274 scoped_refptr<device::HidConnection> connection = resource->connection();
275 const int size = connection->device_info().max_feature_report_size;
276 buffer_ = new net::IOBufferWithSize(size);
277 connection->GetFeatureReport(
278 static_cast<uint8_t>(parameters_->report_id),
280 base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
283 void HidReceiveFeatureReportFunction::OnFinished(bool success, size_t bytes) {
285 CompleteWithError(kErrorTransfer);
289 SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer_->data(), bytes));
290 AsyncWorkCompleted();
293 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
295 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
297 bool HidSendFeatureReportFunction::Prepare() {
298 parameters_ = hid::SendFeatureReport::Params::Create(*args_);
299 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
303 void HidSendFeatureReportFunction::AsyncWorkStart() {
304 int connection_id = parameters_->connection_id;
305 HidConnectionResource* resource =
306 connection_manager_->Get(extension_->id(), connection_id);
308 CompleteWithError(kErrorConnectionNotFound);
311 scoped_refptr<net::IOBufferWithSize> buffer(
312 new net::IOBufferWithSize(parameters_->data.size()));
313 resource->connection()->SendFeatureReport(
314 static_cast<uint8_t>(parameters_->report_id),
316 base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
319 void HidSendFeatureReportFunction::OnFinished(bool success, size_t bytes) {
321 CompleteWithError(kErrorTransfer);
324 AsyncWorkCompleted();
327 } // namespace extensions