blob: f2e150a0ae412a86337bccaced47551b57a4745d [file] [log] [blame]
// Copyright 2017 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.
#pragma once
#include <acpica/acpi.h>
#include <ddktl/device.h>
#include <ddktl/protocol/hidbus.h>
#include <chromiumos-platform-ec/ec_commands.h>
#include <fbl/macros.h>
#include <fbl/mutex.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
class AcpiCrOsEc : public fbl::RefCounted<AcpiCrOsEc> {
public:
static zx_status_t Create(fbl::RefPtr<AcpiCrOsEc>* out);
zx_status_t IssueCommand(uint16_t command, uint8_t command_version,
const void* out, size_t outsize,
void* in, size_t insize, size_t* actual);
bool supports_motion_sense() const {
return features_.flags[0] & EC_FEATURE_MASK_0(EC_FEATURE_MOTION_SENSE);
}
bool supports_motion_sense_fifo() const {
return features_.flags[0] & EC_FEATURE_MASK_0(EC_FEATURE_MOTION_SENSE_FIFO);
}
~AcpiCrOsEc();
private:
AcpiCrOsEc();
DISALLOW_COPY_ASSIGN_AND_MOVE(AcpiCrOsEc);
fbl::Mutex io_lock_;
struct ec_response_get_features features_;
};
// TODO(teisenbe): Define motionsense interface
class AcpiCrOsEcMotionDevice;
using DeviceType = ddk::Device<AcpiCrOsEcMotionDevice>;
// CrOS EC protocol to HID protocol translator for device motion sensors
class AcpiCrOsEcMotionDevice : public DeviceType,
public ddk::HidbusProtocol<AcpiCrOsEcMotionDevice,
ddk::base_protocol> {
public:
static zx_status_t Create(fbl::RefPtr<AcpiCrOsEc> ec,
zx_device_t* parent, ACPI_HANDLE acpi_handle,
fbl::unique_ptr<AcpiCrOsEcMotionDevice>* out);
// hidbus protocol implementation
zx_status_t HidbusQuery(uint32_t options, hid_info_t* info);
zx_status_t HidbusStart(const hidbus_ifc_t* ifc);
void HidbusStop();
zx_status_t HidbusGetDescriptor(uint8_t desc_type, void** data, size_t* len);
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 DdkRelease();
~AcpiCrOsEcMotionDevice();
private:
AcpiCrOsEcMotionDevice(fbl::RefPtr<AcpiCrOsEc> ec, zx_device_t* parent,
ACPI_HANDLE acpi_handle);
DISALLOW_COPY_ASSIGN_AND_MOVE(AcpiCrOsEcMotionDevice);
struct SensorInfo {
bool valid;
enum motionsensor_type type;
enum motionsensor_location loc;
uint32_t min_sampling_freq;
uint32_t max_sampling_freq;
uint32_t fifo_max_event_count;
// For MOTIONSENSE_TYPE_ACCEL, value is in Gs
// MOTIONSENSE_TYPE_GYRO, value is in deg/s
// MOTIONSENSE_TYPE_MAG, value is in multiples of 1/16 uT
// MOTIONSENSE_TYPE_LIGHT, value is in lux?
int32_t phys_min;
int32_t phys_max;
};
static void NotifyHandler(ACPI_HANDLE handle, UINT32 value, void* ctx);
// Hardware commands
zx_status_t QueryNumSensors(uint8_t* count);
zx_status_t QuerySensorInfo(uint8_t sensor_num, SensorInfo* info);
zx_status_t SetEcSamplingRate(uint8_t sensor_num, uint32_t milliseconds);
zx_status_t SetSensorOutputDataRate(uint8_t sensor_num, uint32_t freq_millihertz);
zx_status_t GetSensorRange(uint8_t sensor_num, int32_t* range);
zx_status_t GetKbWakeAngle(int32_t* angle);
zx_status_t SetKbWakeAngle(int16_t angle);
zx_status_t FifoInterruptEnable(bool enable);
zx_status_t FifoRead(struct ec_response_motion_sensor_data* data);
// Guard against concurrent use of the HID interfaces
fbl::Mutex hid_lock_;
void QueueHidReportLocked(const uint8_t* data, size_t len);
zx_status_t ConsumeFifoLocked();
// Chat with hardware to build up |sensors_|
zx_status_t ProbeSensors();
// Populate |hid_descriptor_| based on the contents of |sensors_|
zx_status_t BuildHidDescriptor();
fbl::RefPtr<AcpiCrOsEc> ec_;
const ACPI_HANDLE acpi_handle_;
// Interface the driver is currently bound to
ddk::HidbusIfcClient client_;
fbl::Vector<SensorInfo> sensors_;
fbl::unique_ptr<uint8_t[]> hid_descriptor_ = nullptr;
size_t hid_descriptor_len_ = 0;
};