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/core/device_client.h"
11 #include "device/hid/hid_connection.h"
12 #include "device/hid/hid_device_filter.h"
13 #include "device/hid/hid_device_info.h"
14 #include "device/hid/hid_service.h"
15 #include "extensions/browser/api/api_resource_manager.h"
16 #include "extensions/common/api/hid.h"
17 #include "net/base/io_buffer.h"
19 namespace hid
= extensions::core_api::hid
;
21 using device::HidConnection
;
22 using device::HidDeviceFilter
;
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();
41 void ConvertHidDeviceFilter(linked_ptr
<hid::DeviceFilter
> input
,
42 HidDeviceFilter
* output
) {
43 if (input
->vendor_id
) {
44 output
->SetVendorId(*input
->vendor_id
);
46 if (input
->product_id
) {
47 output
->SetProductId(*input
->product_id
);
49 if (input
->usage_page
) {
50 output
->SetUsagePage(*input
->usage_page
);
53 output
->SetUsage(*input
->usage
);
59 namespace extensions
{
61 HidAsyncApiFunction::HidAsyncApiFunction()
62 : device_manager_(NULL
), connection_manager_(NULL
) {}
64 HidAsyncApiFunction::~HidAsyncApiFunction() {}
66 bool HidAsyncApiFunction::PrePrepare() {
67 #if defined(OS_MACOSX)
68 // Migration from FILE thread to UI thread. OS X gets it first.
69 set_work_thread_id(content::BrowserThread::UI
);
71 // TODO(reillyg): Migrate Linux/CrOS and Windows as well.
72 set_work_thread_id(content::BrowserThread::FILE);
74 device_manager_
= HidDeviceManager::Get(browser_context());
75 if (!device_manager_
) {
79 ApiResourceManager
<HidConnectionResource
>::Get(browser_context());
80 if (!connection_manager_
) {
86 bool HidAsyncApiFunction::Respond() { return error_
.empty(); }
88 HidConnectionResource
* HidAsyncApiFunction::GetHidConnectionResource(
89 int api_resource_id
) {
90 return connection_manager_
->Get(extension_
->id(), api_resource_id
);
93 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id
) {
94 connection_manager_
->Remove(extension_
->id(), api_resource_id
);
97 void HidAsyncApiFunction::CompleteWithError(const std::string
& error
) {
102 HidGetDevicesFunction::HidGetDevicesFunction() {}
104 HidGetDevicesFunction::~HidGetDevicesFunction() {}
106 bool HidGetDevicesFunction::Prepare() {
107 parameters_
= hid::GetDevices::Params::Create(*args_
);
108 EXTENSION_FUNCTION_VALIDATE(parameters_
.get());
112 void HidGetDevicesFunction::AsyncWorkStart() {
113 std::vector
<HidDeviceFilter
> filters
;
114 if (parameters_
->options
.filters
) {
115 filters
.resize(parameters_
->options
.filters
->size());
116 for (size_t i
= 0; i
< parameters_
->options
.filters
->size(); ++i
) {
117 ConvertHidDeviceFilter(parameters_
->options
.filters
->at(i
), &filters
[i
]);
120 if (parameters_
->options
.vendor_id
) {
121 HidDeviceFilter legacy_filter
;
122 legacy_filter
.SetVendorId(*parameters_
->options
.vendor_id
);
123 if (parameters_
->options
.product_id
) {
124 legacy_filter
.SetProductId(*parameters_
->options
.product_id
);
126 filters
.push_back(legacy_filter
);
129 SetResult(device_manager_
->GetApiDevices(extension(), filters
).release());
130 AsyncWorkCompleted();
133 HidConnectFunction::HidConnectFunction() {}
135 HidConnectFunction::~HidConnectFunction() {}
137 bool HidConnectFunction::Prepare() {
138 parameters_
= hid::Connect::Params::Create(*args_
);
139 EXTENSION_FUNCTION_VALIDATE(parameters_
.get());
143 void HidConnectFunction::AsyncWorkStart() {
144 HidDeviceInfo device_info
;
145 if (!device_manager_
->GetDeviceInfo(parameters_
->device_id
, &device_info
)) {
146 CompleteWithError(kErrorInvalidDeviceId
);
150 if (!device_manager_
->HasPermission(extension(), device_info
)) {
151 LOG(WARNING
) << "Insufficient permissions to access device.";
152 CompleteWithError(kErrorPermissionDenied
);
156 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
159 hid_service
->Connect(
160 device_info
.device_id
,
161 base::Bind(&HidConnectFunction::OnConnectComplete
, this));
164 void HidConnectFunction::OnConnectComplete(
165 scoped_refptr
<HidConnection
> connection
) {
166 if (!connection
.get()) {
167 CompleteWithError(kErrorFailedToOpenDevice
);
171 int connection_id
= connection_manager_
->Add(
172 new HidConnectionResource(extension_
->id(), connection
));
173 SetResult(PopulateHidConnection(connection_id
, connection
));
174 AsyncWorkCompleted();
177 HidDisconnectFunction::HidDisconnectFunction() {}
179 HidDisconnectFunction::~HidDisconnectFunction() {}
181 bool HidDisconnectFunction::Prepare() {
182 parameters_
= hid::Disconnect::Params::Create(*args_
);
183 EXTENSION_FUNCTION_VALIDATE(parameters_
.get());
187 void HidDisconnectFunction::AsyncWorkStart() {
188 int connection_id
= parameters_
->connection_id
;
189 HidConnectionResource
* resource
=
190 connection_manager_
->Get(extension_
->id(), connection_id
);
192 CompleteWithError(kErrorConnectionNotFound
);
195 connection_manager_
->Remove(extension_
->id(), connection_id
);
196 AsyncWorkCompleted();
199 HidReceiveFunction::HidReceiveFunction() {}
201 HidReceiveFunction::~HidReceiveFunction() {}
203 bool HidReceiveFunction::Prepare() {
204 parameters_
= hid::Receive::Params::Create(*args_
);
205 EXTENSION_FUNCTION_VALIDATE(parameters_
.get());
209 void HidReceiveFunction::AsyncWorkStart() {
210 int connection_id
= parameters_
->connection_id
;
211 HidConnectionResource
* resource
=
212 connection_manager_
->Get(extension_
->id(), connection_id
);
214 CompleteWithError(kErrorConnectionNotFound
);
218 scoped_refptr
<device::HidConnection
> connection
= resource
->connection();
219 connection
->Read(base::Bind(&HidReceiveFunction::OnFinished
, this));
222 void HidReceiveFunction::OnFinished(bool success
,
223 scoped_refptr
<net::IOBuffer
> buffer
,
226 CompleteWithError(kErrorTransfer
);
231 int report_id
= reinterpret_cast<uint8_t*>(buffer
->data())[0];
233 scoped_ptr
<base::ListValue
> result(new base::ListValue());
234 result
->Append(new base::FundamentalValue(report_id
));
236 base::BinaryValue::CreateWithCopiedBuffer(buffer
->data() + 1, size
- 1));
237 SetResultList(result
.Pass());
238 AsyncWorkCompleted();
241 HidSendFunction::HidSendFunction() {}
243 HidSendFunction::~HidSendFunction() {}
245 bool HidSendFunction::Prepare() {
246 parameters_
= hid::Send::Params::Create(*args_
);
247 EXTENSION_FUNCTION_VALIDATE(parameters_
.get());
251 void HidSendFunction::AsyncWorkStart() {
252 int connection_id
= parameters_
->connection_id
;
253 HidConnectionResource
* resource
=
254 connection_manager_
->Get(extension_
->id(), connection_id
);
256 CompleteWithError(kErrorConnectionNotFound
);
260 scoped_refptr
<net::IOBufferWithSize
> buffer(
261 new net::IOBufferWithSize(parameters_
->data
.size() + 1));
262 buffer
->data()[0] = static_cast<uint8_t>(parameters_
->report_id
);
264 buffer
->data() + 1, parameters_
->data
.c_str(), parameters_
->data
.size());
265 resource
->connection()->Write(
266 buffer
, buffer
->size(), base::Bind(&HidSendFunction::OnFinished
, this));
269 void HidSendFunction::OnFinished(bool success
) {
271 CompleteWithError(kErrorTransfer
);
274 AsyncWorkCompleted();
277 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
279 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
281 bool HidReceiveFeatureReportFunction::Prepare() {
282 parameters_
= hid::ReceiveFeatureReport::Params::Create(*args_
);
283 EXTENSION_FUNCTION_VALIDATE(parameters_
.get());
287 void HidReceiveFeatureReportFunction::AsyncWorkStart() {
288 int connection_id
= parameters_
->connection_id
;
289 HidConnectionResource
* resource
=
290 connection_manager_
->Get(extension_
->id(), connection_id
);
292 CompleteWithError(kErrorConnectionNotFound
);
296 scoped_refptr
<device::HidConnection
> connection
= resource
->connection();
297 connection
->GetFeatureReport(
298 static_cast<uint8_t>(parameters_
->report_id
),
299 base::Bind(&HidReceiveFeatureReportFunction::OnFinished
, this));
302 void HidReceiveFeatureReportFunction::OnFinished(
304 scoped_refptr
<net::IOBuffer
> buffer
,
307 CompleteWithError(kErrorTransfer
);
311 SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer
->data(), size
));
312 AsyncWorkCompleted();
315 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
317 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
319 bool HidSendFeatureReportFunction::Prepare() {
320 parameters_
= hid::SendFeatureReport::Params::Create(*args_
);
321 EXTENSION_FUNCTION_VALIDATE(parameters_
.get());
325 void HidSendFeatureReportFunction::AsyncWorkStart() {
326 int connection_id
= parameters_
->connection_id
;
327 HidConnectionResource
* resource
=
328 connection_manager_
->Get(extension_
->id(), connection_id
);
330 CompleteWithError(kErrorConnectionNotFound
);
334 scoped_refptr
<net::IOBufferWithSize
> buffer(
335 new net::IOBufferWithSize(parameters_
->data
.size() + 1));
336 buffer
->data()[0] = static_cast<uint8_t>(parameters_
->report_id
);
338 buffer
->data() + 1, parameters_
->data
.c_str(), parameters_
->data
.size());
339 resource
->connection()->SendFeatureReport(
342 base::Bind(&HidSendFeatureReportFunction::OnFinished
, this));
345 void HidSendFeatureReportFunction::OnFinished(bool success
) {
347 CompleteWithError(kErrorTransfer
);
350 AsyncWorkCompleted();
353 } // namespace extensions