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 <ddk/driver.h> 8#include <ddk/protocol/hidbus.h> 9#include <ddktl/protocol/hidbus-internal.h> 10#include <fbl/type_support.h> 11#include <fbl/unique_ptr.h> 12#include <zircon/assert.h> 13 14// DDK hidbus protocol support 15// 16// :: Proxies :: 17// 18// ddk::HidBusIfcProxy is simple wrappers around hidbus_ifc_t. It does not own the pointers passed 19// to it. 20// 21// :: Mixins :: 22// 23// ddk::HidBusProtocol is a mixin class that simplifies writing DDK drivers that 24// implement the hidbus protocol. They take care of implementing the function pointer tables 25// and calling into the object that wraps them. 26// 27// :: Examples :: 28// 29// // A driver that implements a ZX_PROTOCOL_HIDBUS device 30// class HidBusDevice; 31// using HidBusDeviceType = ddk::Device<HidBusDevice, /* ddk mixins */>; 32// 33// class HidBusDevice : public HidBusDeviceType, 34// public ddk::HidBusProtocol<HidBusDevice> { 35// public: 36// HidBusDevice(zx_device_t* parent) 37// : HidBusDeviceType(parent) {} 38// 39// zx_status_t Bind() { 40// DdkAdd(); 41// } 42// 43// void DdkRelease() { 44// // Clean up 45// } 46// 47// zx_status_t HidBusStart(ddk::HidBusIfcProxy proxy) { 48// // Start hidbus operation 49// proxy_ = proxy; 50// return ZX_OK; 51// } 52// 53// zx_status_t HidBusQuery(uint32_t options, hid_info_t* info) { 54// ... 55// } 56// 57// ... 58// private: 59// ddk::HidBusIfcProxy proxy_; 60// ... 61// }; 62 63namespace ddk { 64 65class HidBusIfcProxy { 66public: 67 HidBusIfcProxy() 68 : ifc_(nullptr), cookie_(nullptr) {} 69 70 HidBusIfcProxy(hidbus_ifc_t* ifc, void* cookie) 71 : ifc_(ifc), cookie_(cookie) {} 72 73 void IoQueue(const uint8_t* buf, size_t len) { 74 ifc_->io_queue(cookie_, buf, len); 75 } 76 77 bool is_valid() const { 78 return ifc_ != nullptr; 79 } 80 81 void clear() { 82 ifc_ = nullptr; 83 cookie_ = nullptr; 84 } 85 86private: 87 hidbus_ifc_t* ifc_; 88 void* cookie_; 89}; 90 91template <typename D> 92class HidBusProtocol : public internal::base_protocol { 93public: 94 HidBusProtocol() { 95 internal::CheckHidBusProtocolSubclass<D>(); 96 ops_.query = Query; 97 ops_.start = Start; 98 ops_.stop = Stop; 99 ops_.get_descriptor = GetDescriptor; 100 ops_.get_report = GetReport; 101 ops_.set_report = SetReport; 102 ops_.get_idle = GetIdle; 103 ops_.set_idle = SetIdle; 104 ops_.get_protocol = GetProtocol; 105 ops_.set_protocol = SetProtocol; 106 107 // Can only inherit from one base_protocol implemenation 108 ZX_ASSERT(ddk_proto_id_ == 0); 109 ddk_proto_id_ = ZX_PROTOCOL_HIDBUS; 110 ddk_proto_ops_ = &ops_; 111 } 112 113private: 114 static zx_status_t Query(void* ctx, uint32_t options, hid_info_t* info) { 115 return static_cast<D*>(ctx)->HidBusQuery(options, info); 116 } 117 118 static zx_status_t Start(void* ctx, hidbus_ifc_t* ifc, void* cookie) { 119 HidBusIfcProxy proxy(ifc, cookie); 120 return static_cast<D*>(ctx)->HidBusStart(proxy); 121 } 122 123 static void Stop(void* ctx) { 124 static_cast<D*>(ctx)->HidBusStop(); 125 } 126 127 static zx_status_t GetDescriptor(void* ctx, uint8_t desc_type, void** data, size_t* len) { 128 return static_cast<D*>(ctx)->HidBusGetDescriptor(desc_type, data, len); 129 } 130 131 static zx_status_t GetReport(void* ctx, uint8_t rpt_type, uint8_t rpt_id, void* data, 132 size_t len, size_t* out_len) { 133 return static_cast<D*>(ctx)->HidBusGetReport(rpt_type, rpt_id, data, len, out_len); 134 } 135 136 static zx_status_t SetReport(void* ctx, uint8_t rpt_type, uint8_t rpt_id, void* data, 137 size_t len) { 138 return static_cast<D*>(ctx)->HidBusSetReport(rpt_type, rpt_id, data, len); 139 } 140 141 static zx_status_t GetIdle(void* ctx, uint8_t rpt_id, uint8_t* duration) { 142 return static_cast<D*>(ctx)->HidBusGetIdle(rpt_id, duration); 143 } 144 145 static zx_status_t SetIdle(void* ctx, uint8_t rpt_id, uint8_t duration) { 146 return static_cast<D*>(ctx)->HidBusSetIdle(rpt_id, duration); 147 } 148 149 static zx_status_t GetProtocol(void* ctx, uint8_t* protocol) { 150 return static_cast<D*>(ctx)->HidBusGetProtocol(protocol); 151 } 152 153 static zx_status_t SetProtocol(void* ctx, uint8_t protocol) { 154 return static_cast<D*>(ctx)->HidBusSetProtocol(protocol); 155 } 156 157 hidbus_protocol_ops_t ops_ = {}; 158}; 159 160} // namespace ddk 161