blob: df2b538027186c61a74e08dde1e1104cafd88f40 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ui/lib/input_reader/fdio_hid_decoder.h"
#include <fuchsia/device/llcpp/fidl.h>
#include <fuchsia/hardware/input/c/fidl.h>
#include <unistd.h>
#include <zircon/status.h>
#include <hid/acer12.h>
#include <hid/egalax.h>
#include <hid/eyoyo.h>
#include <hid/ft3x27.h>
#include <hid/paradise.h>
#include <hid/samsung.h>
#include <trace/event.h>
#include "src/lib/fxl/arraysize.h"
#include "src/lib/fxl/logging.h"
namespace {
bool log_err(zx_status_t status, const std::string& what, const std::string& name) {
FXL_LOG(ERROR) << "hid: could not get " << what << " from " << name
<< " (status=" << zx_status_get_string(status) << ")";
return false;
}
} // namespace
namespace ui_input {
FdioHidDecoder::FdioHidDecoder(const std::string& name, fbl::unique_fd fd)
: caller_(std::move(fd)), name_(name) {}
FdioHidDecoder::~FdioHidDecoder() = default;
bool FdioHidDecoder::Init() {
zx_status_t status;
zx_handle_t svc = caller_.borrow_channel();
// Get the Boot Protocol if there is one.
fuchsia_hardware_input_BootProtocol boot_protocol;
status = fuchsia_hardware_input_DeviceGetBootProtocol(svc, &boot_protocol);
if (status != ZX_OK) {
return log_err(status, "boot protocol", name_);
}
if (boot_protocol == fuchsia_hardware_input_BootProtocol_KBD) {
boot_mode_ = BootMode::KEYBOARD;
} else if (boot_protocol == fuchsia_hardware_input_BootProtocol_MOUSE) {
boot_mode_ = BootMode::MOUSE;
} else {
boot_mode_ = BootMode::NONE;
}
// Get the report descriptor.
uint16_t report_desc_len;
status = fuchsia_hardware_input_DeviceGetReportDescSize(svc, &report_desc_len);
if (status != ZX_OK)
return log_err(status, "report descriptor length", name_);
report_descriptor_.resize(report_desc_len);
size_t actual;
status = fuchsia_hardware_input_DeviceGetReportDesc(svc, report_descriptor_.data(),
report_descriptor_.size(), &actual);
if (status != ZX_OK)
return log_err(status, "report descriptor", name_);
report_descriptor_.resize(actual);
// Use lower 32 bits of channel koid as trace ID.
zx_info_handle_basic_t info;
zx_object_get_info(svc, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
trace_id_ = info.koid & 0xffffffff;
status = fuchsia_hardware_input_DeviceSetTraceId(svc, trace_id_);
if (status != ZX_OK)
return log_err(status, "failed to set trace ID", name_);
return true;
}
zx::event FdioHidDecoder::GetEvent() {
zx::event event;
auto resp = ::llcpp::fuchsia::device::Controller::Call::GetEventHandle(
zx::unowned_channel(caller_.borrow_channel()));
zx_status_t status = resp.status();
if (status == ZX_OK) {
event = std::move(resp->event);
}
if (status != ZX_OK) {
log_err(status, "event handle", name_);
return {};
}
return event;
}
const std::vector<uint8_t>& FdioHidDecoder::ReadReportDescriptor(int* bytes_read) {
*bytes_read = report_descriptor_.size();
return report_descriptor_;
}
size_t FdioHidDecoder::Read(uint8_t* data, size_t data_size) {
size_t size;
zx_status_t call_status;
zx_status_t status = fuchsia_hardware_input_DeviceGetReports(
caller_.borrow_channel(), &call_status, data, data_size, &size);
if ((call_status != ZX_OK) || (status != ZX_OK)) {
return 0;
}
return size;
}
zx_status_t FdioHidDecoder::Send(ReportType type, uint8_t report_id,
const std::vector<uint8_t>& report) {
FXL_CHECK(type != ReportType::INPUT);
fuchsia_hardware_input_ReportType fidl_report_type;
switch (type) {
case ReportType::INPUT:
fidl_report_type = fuchsia_hardware_input_ReportType_INPUT;
break;
case ReportType::OUTPUT:
fidl_report_type = fuchsia_hardware_input_ReportType_OUTPUT;
break;
case ReportType::FEATURE:
fidl_report_type = fuchsia_hardware_input_ReportType_FEATURE;
break;
}
zx_handle_t svc = caller_.borrow_channel();
zx_status_t call_status;
zx_status_t status = fuchsia_hardware_input_DeviceSetReport(
svc, fidl_report_type, report_id, report.data(), report.size(), &call_status);
if (status != ZX_OK) {
return status;
} else if (call_status != ZX_OK) {
return call_status;
}
return ZX_OK;
}
zx_status_t FdioHidDecoder::GetReport(ReportType type, uint8_t report_id,
std::vector<uint8_t>* report) {
zx_status_t res, call_status;
uint16_t size;
fuchsia_hardware_input_ReportType real_type;
switch (type) {
case ReportType::INPUT:
real_type = fuchsia_hardware_input_ReportType_INPUT;
break;
case ReportType::OUTPUT:
real_type = fuchsia_hardware_input_ReportType_OUTPUT;
break;
case ReportType::FEATURE:
real_type = fuchsia_hardware_input_ReportType_FEATURE;
break;
}
res = fuchsia_hardware_input_DeviceGetReportSize(caller_.borrow_channel(), real_type, report_id,
&call_status, &size);
if (res != ZX_OK || call_status != ZX_OK) {
FXL_LOG(ERROR) << "hid: could not get report (id " << report_id << " type " << real_type
<< ") size (status=" << zx_status_get_string(res) << ", "
<< zx_status_get_string(call_status) << ")";
return call_status;
}
report->resize(size);
size_t actual;
res =
fuchsia_hardware_input_DeviceGetReport(caller_.borrow_channel(), real_type, report_id,
&call_status, report->data(), report->size(), &actual);
if (res != ZX_OK || call_status != ZX_OK) {
FXL_LOG(ERROR) << "hid: could not get report: " << zx_status_get_string(res) << " "
<< zx_status_get_string(call_status);
return call_status;
}
report->resize(actual);
return ZX_OK;
}
} // namespace ui_input