blob: e31a2a9534442a93defdb3eef75c03fec5340a9b [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 <lib/fdio/fdio.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/files/unique_fd.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, fxl::UniqueFD fd)
: name_(name), fd_(std::move(fd)) {}
FdioHidDecoder::~FdioHidDecoder() = default;
bool FdioHidDecoder::Init() {
zx::channel chan;
zx_status_t status = fdio_get_service_handle(fd_.release(), chan.reset_and_get_address());
if (status != ZX_OK) {
return false;
}
device_ = llcpp::fuchsia::hardware::input::Device::SyncClient(std::move(chan));
// Get the Boot Protocol if there is one.
{
auto result = device_.GetBootProtocol();
if (result.status() != ZX_OK) {
return log_err(status, "boot protocol", name_);
}
if (result->protocol == llcpp::fuchsia::hardware::input::BootProtocol::KBD) {
boot_mode_ = BootMode::KEYBOARD;
} else if (result->protocol == llcpp::fuchsia::hardware::input::BootProtocol::MOUSE) {
boot_mode_ = BootMode::MOUSE;
} else {
boot_mode_ = BootMode::NONE;
}
}
// Get the report descriptor.
{
auto result = device_.GetReportDesc();
if (result.status() != ZX_OK)
return log_err(status, "report descriptor", name_);
report_descriptor_.resize(result->desc.count());
memcpy(report_descriptor_.data(), result->desc.data(), result->desc.count());
}
// Use lower 32 bits of channel koid as trace ID.
{
zx_info_handle_basic_t info;
zx_object_get_info(device_.channel().get(), ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr,
nullptr);
trace_id_ = info.koid & 0xffffffff;
auto result = device_.SetTraceId(trace_id_);
if (result.status() != ZX_OK)
return log_err(status, "failed to set trace ID", name_);
}
return true;
}
zx::event FdioHidDecoder::GetEvent() {
zx::event event;
auto result = device_.GetReportsEvent();
if (result.status() != ZX_OK) {
log_err(result.status(), "event handle", name_);
return event;
}
if (result->status != ZX_OK) {
log_err(result->status, "event handle", name_);
return event;
}
event = std::move(result->event);
return event;
}
const std::vector<uint8_t>& FdioHidDecoder::ReadReportDescriptor(int* bytes_read) {
*bytes_read = report_descriptor_.size();
return report_descriptor_;
}
zx_status_t FdioHidDecoder::Read(uint8_t* data, size_t data_size, size_t* report_size,
zx_time_t* timestamp) {
auto result = device_.ReadReport();
if (result.status() != ZX_OK) {
return result.status();
}
if (result->status != ZX_OK) {
return result->status;
}
if (result->data.count() > data_size) {
return ZX_ERR_BUFFER_TOO_SMALL;
}
memcpy(data, result->data.data(), result->data.count());
*report_size = result->data.count();
*timestamp = result->time;
return ZX_OK;
}
zx_status_t FdioHidDecoder::Send(ReportType type, uint8_t report_id,
const std::vector<uint8_t>& report) {
FXL_CHECK(type != ReportType::INPUT);
llcpp::fuchsia::hardware::input::ReportType fidl_report_type;
switch (type) {
case ReportType::INPUT:
fidl_report_type = llcpp::fuchsia::hardware::input::ReportType::INPUT;
break;
case ReportType::OUTPUT:
fidl_report_type = llcpp::fuchsia::hardware::input::ReportType::OUTPUT;
break;
case ReportType::FEATURE:
fidl_report_type = llcpp::fuchsia::hardware::input::ReportType::FEATURE;
break;
}
// This is a little unwieldy but we need a non-const version of `report` to make
// the FIDL call, so we have to make a copy.
std::vector<uint8_t> report_copy = report;
fidl::VectorView<uint8_t> report_view(fidl::unowned_ptr<uint8_t>(report_copy.data()),
report_copy.size());
auto result = device_.SetReport(fidl_report_type, report_id, std::move(report_view));
if (result.status() != ZX_OK) {
return result.status();
}
if (result->status != ZX_OK) {
return result->status;
}
return ZX_OK;
}
zx_status_t FdioHidDecoder::GetReport(ReportType type, uint8_t report_id,
std::vector<uint8_t>* report) {
llcpp::fuchsia::hardware::input::ReportType real_type;
switch (type) {
case ReportType::INPUT:
real_type = llcpp::fuchsia::hardware::input::ReportType::INPUT;
break;
case ReportType::OUTPUT:
real_type = llcpp::fuchsia::hardware::input::ReportType::OUTPUT;
break;
case ReportType::FEATURE:
real_type = llcpp::fuchsia::hardware::input::ReportType::FEATURE;
break;
}
auto result = device_.GetReport(real_type, report_id);
if (result.status() != ZX_OK) {
FXL_LOG(ERROR) << "hid: get report failed " << zx_status_get_string(result.status());
return result.status();
}
if (result->status != ZX_OK) {
FXL_LOG(ERROR) << "hid: could not get report (id " << report_id << " type "
<< static_cast<uint8_t>(real_type)
<< ") (status=" << zx_status_get_string(result->status) << ")";
return result->status;
}
report->resize(result->report.count());
memcpy(report->data(), result->report.data(), result->report.count());
return ZX_OK;
}
} // namespace ui_input