blob: 3a89d7e2ccdf39690c0a442e1d81067c974b96f6 [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_UI_INPUT_DRIVERS_USB_HID_USB_HID_H_
#define SRC_UI_INPUT_DRIVERS_USB_HID_USB_HID_H_
#include <fidl/fuchsia.hardware.hidbus/cpp/wire.h>
#include <fidl/fuchsia.hardware.usb/cpp/fidl.h>
#include <fuchsia/hardware/usb/cpp/banjo.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/sync/completion.h>
#include <thread>
#include <fbl/condition_variable.h>
#include <fbl/mutex.h>
#include <usb-endpoint/usb-endpoint-client.h>
#include <usb/hid.h>
#include <usb/usb.h>
namespace usb_hid {
class UsbHidbus : public fdf::DriverBase, public fidl::WireServer<fuchsia_hardware_hidbus::Hidbus> {
public:
static constexpr std::string_view kDriverName = "usb_hid";
static constexpr std::string_view kChildNodeName = "usb-hid";
UsbHidbus(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: DriverBase(kDriverName, std::move(start_args), std::move(driver_dispatcher)) {}
// fdf::DriverBase implementation.
void Start(fdf::StartCompleter completer) override { completer(Start()); }
zx::result<> Start() override;
void PrepareStop(fdf::PrepareStopCompleter completer) override;
void Stop() override;
// fidl::WireServer<fuchsia_hardware_hidbus::Hidbus> implementation.
void Query(QueryCompleter::Sync& completer) override;
void Start(
fidl::WireServer<fuchsia_hardware_hidbus::Hidbus>::StartCompleter::Sync& completer) override;
void Stop(StopCompleter::Sync& completer) override;
void GetDescriptor(fuchsia_hardware_hidbus::wire::HidbusGetDescriptorRequest* request,
GetDescriptorCompleter::Sync& completer) override;
void SetDescriptor(fuchsia_hardware_hidbus::wire::HidbusSetDescriptorRequest* request,
SetDescriptorCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void GetReport(fuchsia_hardware_hidbus::wire::HidbusGetReportRequest* request,
GetReportCompleter::Sync& completer) override;
void SetReport(fuchsia_hardware_hidbus::wire::HidbusSetReportRequest* request,
SetReportCompleter::Sync& completer) override;
void GetIdle(fuchsia_hardware_hidbus::wire::HidbusGetIdleRequest* request,
GetIdleCompleter::Sync& completer) override;
void SetIdle(fuchsia_hardware_hidbus::wire::HidbusSetIdleRequest* request,
SetIdleCompleter::Sync& completer) override;
void GetProtocol(GetProtocolCompleter::Sync& completer) override;
void SetProtocol(fuchsia_hardware_hidbus::wire::HidbusSetProtocolRequest* request,
SetProtocolCompleter::Sync& completer) override;
zx_status_t UsbHidControl(uint8_t req_type, uint8_t request, uint16_t value, uint16_t index,
void* data, size_t length, size_t* out_length);
zx_status_t UsbHidControlIn(uint8_t req_type, uint8_t request, uint16_t value, uint16_t index,
void* data, size_t length, size_t* out_length);
zx_status_t UsbHidControlOut(uint8_t req_type, uint8_t request, uint16_t value, uint16_t index,
const void* data, size_t length, size_t* out_length);
void UsbHidRelease();
static void FindDescriptors(usb::Interface interface, const usb_hid_descriptor_t** hid_desc,
const usb_endpoint_descriptor_t** endptin,
const usb_endpoint_descriptor_t** endptout);
private:
void StopHidbus();
void HandleInterrupt(fuchsia_hardware_usb_endpoint::Completion completion);
void SetReportComplete(fuchsia_hardware_usb_endpoint::Completion completion);
async::Loop dispatcher_loop_{&kAsyncLoopConfigNeverAttachToThread};
std::optional<fidl::ServerBinding<fuchsia_hardware_hidbus::Hidbus>> binding_;
std::atomic_bool started_ = false;
std::optional<usb::InterfaceList> usb_interface_list_;
// These pointers are valid as long as usb_interface_list_ is valid.
const usb_hid_descriptor_t* hid_desc_ = nullptr;
fidl::Arena<> arena_;
fuchsia_hardware_hidbus::wire::HidInfo info_;
ddk::UsbProtocolClient usb_;
uint8_t interface_ = 0;
usb_desc_iter_t desc_iter_ = {};
size_t parent_req_size_ = 0;
std::thread unbind_thread_;
std::optional<SetReportCompleter::Async> set_report_completer_;
// Interrupt endpoint
usb::EndpointClient<UsbHidbus> ep_in_{usb::EndpointType::INTERRUPT, this,
std::mem_fn(&UsbHidbus::HandleInterrupt)};
std::optional<usb::EndpointClient<UsbHidbus>> ep_out_;
fidl::ClientEnd<fuchsia_driver_framework::NodeController> child_;
};
} // namespace usb_hid
#endif // SRC_UI_INPUT_DRIVERS_USB_HID_USB_HID_H_