blob: c45c8db284f7dceaaafc94464fc5cb928ff7b105 [file] [log] [blame]
// Copyright 2019 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 "instance.h"
#include <ddk/debug.h>
#include <ddktl/fidl.h>
#include <fbl/auto_lock.h>
namespace input_report_instance {
zx_status_t InputReportInstance::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) {
DdkTransaction transaction(txn);
fuchsia_input_report::InputDevice::Dispatch(this, msg, &transaction);
return transaction.Status();
}
zx_status_t InputReportInstance::Bind(InputReportBase* base) {
base_ = base;
zx_status_t status = zx::event::create(0, &reports_event_);
if (status != ZX_OK) {
return status;
}
return DdkAdd("input-report-instance", DEVICE_ADD_INSTANCE);
}
zx_status_t InputReportInstance::DdkClose(uint32_t flags) {
base_->RemoveInstanceFromList(this);
return ZX_OK;
}
void InputReportInstance::GetReportsEvent(GetReportsEventCompleter::Sync _completer) {
zx::event new_event;
zx_status_t status;
{
fbl::AutoLock lock(&report_lock_);
status = reports_event_.duplicate(ZX_RIGHTS_BASIC, &new_event);
}
_completer.Reply(status, std::move(new_event));
}
void InputReportInstance::GetDescriptor(GetDescriptorCompleter::Sync _completer) {
hid_input_report::FidlDescriptor descriptor_data = {};
fuchsia_input_report::DeviceDescriptor descriptor;
size_t size;
const hid_input_report::ReportDescriptor* descriptors = base_->GetDescriptors(&size);
zx_status_t status;
for (size_t i = 0; i < size; i++) {
status = hid_input_report::SetFidlDescriptor(descriptors[i], &descriptor_data);
if (status != ZX_OK) {
break;
}
}
descriptor = descriptor_data.builder.build();
_completer.Reply(std::move(descriptor));
}
void InputReportInstance::GetReports(GetReportsCompleter::Sync _completer) {
fbl::AutoLock lock(&report_lock_);
size_t index = 0;
zx_status_t status = ZX_OK;
while (!reports_data_.empty()) {
status =
hid_input_report::SetFidlInputReport(reports_data_.front(), &reports_fidl_data_[index]);
reports_data_.pop();
if (status != ZX_OK) {
break;
}
reports_[index] = reports_fidl_data_[index].builder.build();
index++;
}
if (reports_data_.empty()) {
reports_event_.signal(DEV_STATE_READABLE, 0);
}
fidl::VectorView<fuchsia_input_report::InputReport> report_view(reports_.data(), index);
_completer.Reply(report_view);
}
void InputReportInstance::SendOutputReport(fuchsia_input_report::OutputReport report,
SendOutputReportCompleter::Sync completer) {
zx_status_t status = base_->SendOutputReport(std::move(report));
if (status != ZX_OK) {
completer.ReplyError(status);
}
completer.ReplySuccess();
}
void InputReportInstance::ReceiveReport(const hid_input_report::InputReport& input_report) {
fbl::AutoLock lock(&report_lock_);
if (reports_data_.empty()) {
reports_event_.signal(0, DEV_STATE_READABLE);
}
// If we are full, pop the oldest report.
if (reports_data_.full()) {
reports_data_.pop();
}
reports_data_.push(input_report);
}
} // namespace input_report_instance