blob: 07fdb041429a72185bcf8b4ca58fc14b55c8ee5a [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.
#ifndef SRC_DEVICES_BOARD_DRIVERS_X86_ACPI_DEV_DEV_LID_H_
#define SRC_DEVICES_BOARD_DRIVERS_X86_ACPI_DEV_DEV_LID_H_
#include <inttypes.h>
#include <lib/fit/function.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <memory>
#include <acpica/acpi.h>
#include <ddktl/device.h>
#include <ddktl/protocol/hidbus.h>
#include <fbl/auto_lock.h>
#include <fbl/mutex.h>
namespace acpi_lid {
enum class LidState {
UNKNOWN = -1, // No observation has been made yet
CLOSED = 0,
OPEN = 1
};
// function pointers for testability, used to mock out ACPI methods where necessary
using AcpiObjectEvalFunc = fit::function<ACPI_STATUS(ACPI_HANDLE, ACPI_STRING, ACPI_OBJECT_LIST*,
ACPI_BUFFER*, ACPI_OBJECT_TYPE)>;
using AcpiInstallNotifyHandlerFunc = fit::function<ACPI_STATUS(
ACPI_HANDLE handle, UINT32 handler_type, ACPI_NOTIFY_HANDLER handler, void* ctx)>;
using AcpiRemoveNotifyHandlerFunc = fit::function<ACPI_STATUS(
ACPI_HANDLE handle, UINT32 handler_type, ACPI_NOTIFY_HANDLER handler)>;
class AcpiLidDevice;
using DeviceType = ddk::Device<AcpiLidDevice, ddk::UnbindableNew>;
// An instance of a PNP0C0D Lid device. It presents a HID interface with a single input, the state
// of the lid switch.
class AcpiLidDevice : public DeviceType,
public ddk::HidbusProtocol<AcpiLidDevice, ddk::base_protocol> {
public:
AcpiLidDevice(zx_device_t* parent, ACPI_HANDLE acpi_handle, AcpiObjectEvalFunc acpi_eval,
AcpiInstallNotifyHandlerFunc acpi_install_notify,
AcpiRemoveNotifyHandlerFunc acpi_remove_notify)
: DeviceType(parent),
acpi_handle_(acpi_handle),
acpi_eval_(std::move(acpi_eval)),
acpi_install_notify_(std::move(acpi_install_notify)),
acpi_remove_notify_(std::move(acpi_remove_notify)) {}
static zx_status_t Create(zx_device_t* parent, ACPI_HANDLE acpi_handle,
std::unique_ptr<AcpiLidDevice>* out) {
return Create(parent, acpi_handle, out, AcpiEvaluateObjectTyped, AcpiInstallNotifyHandler,
AcpiRemoveNotifyHandler);
}
// Exposed for testing
static zx_status_t Create(zx_device_t* parent, ACPI_HANDLE acpi_handle,
std::unique_ptr<AcpiLidDevice>* out, AcpiObjectEvalFunc acpi_eval,
AcpiInstallNotifyHandlerFunc acpi_install_notify,
AcpiRemoveNotifyHandlerFunc acpi_remove_notify);
LidState State() {
fbl::AutoLock guard(&lock_);
return lid_state_;
}
// hidbus protocol implementation
zx_status_t HidbusQuery(uint32_t options, hid_info_t* info);
zx_status_t HidbusStart(const hidbus_ifc_protocol_t* ifc);
void HidbusStop();
zx_status_t HidbusGetDescriptor(hid_description_type_t desc_type, void* out_data_buffer,
size_t data_size, size_t* out_data_actual);
zx_status_t HidbusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len,
size_t* out_len);
zx_status_t HidbusSetReport(uint8_t rpt_type, uint8_t rpt_id, const void* data, size_t len);
zx_status_t HidbusGetIdle(uint8_t rpt_id, uint8_t* duration);
zx_status_t HidbusSetIdle(uint8_t rpt_id, uint8_t duration);
zx_status_t HidbusGetProtocol(uint8_t* protocol);
zx_status_t HidbusSetProtocol(uint8_t protocol);
void DdkUnbindNew(ddk::UnbindTxn txn);
void DdkRelease();
static const uint8_t kHidDescriptor[];
static const size_t kHidDescriptorLen;
static constexpr size_t kHidReportLen = 1;
private:
DISALLOW_COPY_ASSIGN_AND_MOVE(AcpiLidDevice);
static void NotifyHandler(ACPI_HANDLE handle, UINT32 value, void* ctx);
zx_status_t UpdateLidStateLocked() TA_REQ(lock_);
void QueueHidReportLocked() TA_REQ(lock_);
void PublishLidStateIfChanged();
const ACPI_HANDLE acpi_handle_;
fbl::Mutex lock_;
// Current state of the lid switch
LidState lid_state_ TA_GUARDED(lock_) = LidState::UNKNOWN;
// Interface the driver is currently bound to
ddk::HidbusIfcProtocolClient client_ TA_GUARDED(lock_);
const AcpiObjectEvalFunc acpi_eval_;
const AcpiInstallNotifyHandlerFunc acpi_install_notify_;
const AcpiRemoveNotifyHandlerFunc acpi_remove_notify_;
};
} // namespace acpi_lid
#endif // SRC_DEVICES_BOARD_DRIVERS_X86_ACPI_DEV_DEV_LID_H_