1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include <acpica/acpi.h>
8#include <ddktl/device.h>
9#include <ddktl/protocol/hidbus.h>
10#include <chromiumos-platform-ec/ec_commands.h>
11#include <fbl/macros.h>
12#include <fbl/mutex.h>
13#include <fbl/ref_counted.h>
14#include <fbl/ref_ptr.h>
15#include <fbl/vector.h>
16#include <zircon/compiler.h>
17#include <zircon/types.h>
18
19class AcpiCrOsEc : public fbl::RefCounted<AcpiCrOsEc> {
20 public:
21    static zx_status_t Create(fbl::RefPtr<AcpiCrOsEc>* out);
22    zx_status_t IssueCommand(uint16_t command, uint8_t command_version,
23                             const void* out, size_t outsize,
24                             void* in, size_t insize, size_t* actual);
25
26    bool supports_motion_sense() const {
27        return features_.flags[0] & EC_FEATURE_MASK_0(EC_FEATURE_MOTION_SENSE);
28    }
29
30    bool supports_motion_sense_fifo() const {
31        return features_.flags[0] & EC_FEATURE_MASK_0(EC_FEATURE_MOTION_SENSE_FIFO);
32    }
33
34    ~AcpiCrOsEc();
35 private:
36    AcpiCrOsEc();
37    DISALLOW_COPY_ASSIGN_AND_MOVE(AcpiCrOsEc);
38
39    fbl::Mutex io_lock_;
40    struct ec_response_get_features features_;
41};
42
43// TODO(teisenbe): Define motionsense interface
44
45class AcpiCrOsEcMotionDevice;
46using DeviceType = ddk::Device<AcpiCrOsEcMotionDevice>;
47
48// CrOS EC protocol to HID protocol translator for device motion sensors
49class AcpiCrOsEcMotionDevice : public DeviceType,
50                               public ddk::HidBusProtocol<AcpiCrOsEcMotionDevice> {
51public:
52    static zx_status_t Create(fbl::RefPtr<AcpiCrOsEc> ec,
53                              zx_device_t* parent, ACPI_HANDLE acpi_handle,
54                              fbl::unique_ptr<AcpiCrOsEcMotionDevice>* out);
55
56    // hidbus protocol implementation
57    zx_status_t HidBusQuery(uint32_t options, hid_info_t* info);
58    zx_status_t HidBusStart(ddk::HidBusIfcProxy proxy);
59    void HidBusStop();
60    zx_status_t HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len);
61    zx_status_t HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len,
62                                size_t* out_len);
63    zx_status_t HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len);
64    zx_status_t HidBusGetIdle(uint8_t rpt_id, uint8_t* duration);
65    zx_status_t HidBusSetIdle(uint8_t rpt_id, uint8_t duration);
66    zx_status_t HidBusGetProtocol(uint8_t* protocol);
67    zx_status_t HidBusSetProtocol(uint8_t protocol);
68
69    void DdkRelease();
70    ~AcpiCrOsEcMotionDevice();
71private:
72    AcpiCrOsEcMotionDevice(fbl::RefPtr<AcpiCrOsEc> ec, zx_device_t* parent,
73                           ACPI_HANDLE acpi_handle);
74    DISALLOW_COPY_ASSIGN_AND_MOVE(AcpiCrOsEcMotionDevice);
75
76    struct SensorInfo {
77        bool valid;
78
79        enum motionsensor_type type;
80        enum motionsensor_location loc;
81        uint32_t min_sampling_freq;
82        uint32_t max_sampling_freq;
83        uint32_t fifo_max_event_count;
84
85        // For MOTIONSENSE_TYPE_ACCEL, value is in Gs
86        //     MOTIONSENSE_TYPE_GYRO, value is in deg/s
87        //     MOTIONSENSE_TYPE_MAG, value is in multiples of 1/16 uT
88        //     MOTIONSENSE_TYPE_LIGHT, value is in lux?
89        int32_t phys_min;
90        int32_t phys_max;
91    };
92
93    static void NotifyHandler(ACPI_HANDLE handle, UINT32 value, void* ctx);
94
95    // Hardware commands
96    zx_status_t QueryNumSensors(uint8_t* count);
97    zx_status_t QuerySensorInfo(uint8_t sensor_num, SensorInfo* info);
98    zx_status_t SetEcSamplingRate(uint8_t sensor_num, uint32_t milliseconds);
99    zx_status_t SetSensorOutputDataRate(uint8_t sensor_num, uint32_t freq_millihertz);
100    zx_status_t GetSensorRange(uint8_t sensor_num, int32_t* range);
101    zx_status_t GetKbWakeAngle(int32_t* angle);
102    zx_status_t SetKbWakeAngle(int16_t angle);
103    zx_status_t FifoInterruptEnable(bool enable);
104    zx_status_t FifoRead(struct ec_response_motion_sensor_data* data);
105
106    // Guard against concurrent use of the HID interfaces
107    fbl::Mutex hid_lock_;
108    void QueueHidReportLocked(const uint8_t* data, size_t len);
109    zx_status_t ConsumeFifoLocked();
110
111    // Chat with hardware to build up |sensors_|
112    zx_status_t ProbeSensors();
113
114    // Populate |hid_descriptor_| based on the contents of |sensors_|
115    zx_status_t BuildHidDescriptor();
116
117    fbl::RefPtr<AcpiCrOsEc> ec_;
118
119    const ACPI_HANDLE acpi_handle_;
120
121    // Interface the driver is currently bound to
122    ddk::HidBusIfcProxy proxy_;
123
124    fbl::Vector<SensorInfo> sensors_;
125
126    fbl::unique_ptr<uint8_t[]> hid_descriptor_ = nullptr;
127    size_t hid_descriptor_len_ = 0;
128};
129