[hidctl] Rewrite hidctl driver
The hidctl driver was never updated to use the hidbus protocol. This
rewrite leverages the DDKTL and provides a socket over which HID reports
may be injected into a virtual input device.
HID commands are not yet implemented, so only reading input reports is
supported so far.
Change-Id: I5938af3a89bc184e78060f4e61ec4280882bc5bb
diff --git a/system/dev/input/hidctl/binding.c b/system/dev/input/hidctl/binding.c
new file mode 100644
index 0000000..a18689c
--- /dev/null
+++ b/system/dev/input/hidctl/binding.c
@@ -0,0 +1,20 @@
+// 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.
+
+#include <ddk/device.h>
+#include <ddk/driver.h>
+#include <ddk/binding.h>
+
+#include <zircon/types.h>
+
+extern zx_status_t hidctl_bind(void* ctx, zx_device_t* device, void** cookie);
+
+static zx_driver_ops_t hidctl_driver_ops = {
+ .version = DRIVER_OPS_VERSION,
+ .bind = hidctl_bind,
+};
+
+ZIRCON_DRIVER_BEGIN(hidctl, hidctl_driver_ops, "zircon", "0.1", 1)
+ BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_MISC_PARENT),
+ZIRCON_DRIVER_END(hidctl)
diff --git a/system/dev/input/hidctl/hidctl.c b/system/dev/input/hidctl/hidctl.c
deleted file mode 100644
index 7e0ed6e..0000000
--- a/system/dev/input/hidctl/hidctl.c
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2016 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.
-
-#include <ddk/binding.h>
-#include <ddk/device.h>
-#include <ddk/driver.h>
-#include <ddk/common/hid.h>
-
-#include <zircon/device/hidctl.h>
-#include <zircon/types.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define from_hid_device(d) containerof(d, hidctl_instance_t, hiddev)
-
-typedef struct hidctl_instance {
- zx_device_t* zxdev;
- zx_device_t* parent;
- zx_hid_device_t hiddev;
-
- uint8_t* hid_report_desc;
- size_t hid_report_desc_len;
-} hidctl_instance_t;
-
-typedef struct hidctl_root {
- zx_device_t* zxdev;
-} hidctl_root_t;
-
-zx_status_t hidctl_get_descriptor(zx_hid_device_t* dev, uint8_t desc_type, void** data, size_t* len) {
- if (desc_type != HID_DESC_TYPE_REPORT) {
- return ZX_ERR_NOT_SUPPORTED;
- }
- hidctl_instance_t* inst = from_hid_device(dev);
- *data = malloc(inst->hid_report_desc_len);
- memcpy(*data, inst->hid_report_desc, inst->hid_report_desc_len);
- *len = inst->hid_report_desc_len;
- return ZX_OK;
-}
-
-zx_status_t hidctl_get_report(zx_hid_device_t* dev, uint8_t rpt_type, uint8_t rpt_id, void* data,
- size_t len, size_t* out_len) {
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t hidctl_set_report(zx_hid_device_t* dev, uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len) {
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t hidctl_get_idle(zx_hid_device_t* dev, uint8_t rpt_id, uint8_t* duration) {
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t hidctl_set_idle(zx_hid_device_t* dev, uint8_t rpt_id, uint8_t duration) {
- return ZX_OK;
-}
-
-zx_status_t hidctl_get_protocol(zx_hid_device_t* dev, uint8_t* protocol) {
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-zx_status_t hidctl_set_protocol(zx_hid_device_t* dev, uint8_t protocol) {
- return ZX_OK;
-}
-
-static hid_bus_ops_t hidctl_hid_ops = {
- .get_descriptor = hidctl_get_descriptor,
- .get_report = hidctl_get_report,
- .set_report = hidctl_set_report,
- .get_idle = hidctl_get_idle,
- .set_idle = hidctl_set_idle,
- .get_protocol = hidctl_get_protocol,
- .set_protocol = hidctl_set_protocol,
-};
-
-static ssize_t hidctl_set_config(hidctl_instance_t* dev, const void* in_buf, size_t in_len) {
- const hid_ioctl_config_t* cfg = in_buf;
- if (in_len < sizeof(hid_ioctl_config_t) || in_len != sizeof(hid_ioctl_config_t) + cfg->rpt_desc_len) {
- return ZX_ERR_INVALID_ARGS;
- }
-
- if (cfg->dev_class > HID_DEV_CLASS_LAST) {
- return ZX_ERR_INVALID_ARGS;
- }
-
- hid_init_device(&dev->hiddev, &hidctl_hid_ops, cfg->dev_num, cfg->boot_device, cfg->dev_class);
-
- dev->hid_report_desc_len = cfg->rpt_desc_len;
- dev->hid_report_desc = malloc(cfg->rpt_desc_len);
- memcpy(dev->hid_report_desc, cfg->rpt_desc, cfg->rpt_desc_len);
-
- zx_status_t status = hid_add_device(&_driver_hidctl, &dev->hiddev, dev->parent);
- if (status != ZX_OK) {
- hid_release_device(&dev->hiddev);
- free(dev->hid_report_desc);
- dev->hid_report_desc = NULL;
- } else {
- printf("hidctl: device added\n");
- }
- return status;
-}
-
-static ssize_t hidctl_read(void* ctx, void* buf, size_t count, zx_off_t off) {
- return 0;
-}
-
-static ssize_t hidctl_write(void* ctx, const void* buf, size_t count, zx_off_t off) {
- hidctl_instance_t* inst = ctx;
- hid_io_queue(&inst->hiddev, buf, count);
- return count;
-}
-
-static ssize_t hidctl_ioctl(void* ctx, uint32_t op,
- const void* in_buf, size_t in_len, void* out_buf, size_t out_len) {
- hidctl_instance_t* inst = ctx;
- switch (op) {
- case IOCTL_HID_CTL_CONFIG:
- return hidctl_set_config(inst, in_buf, in_len);
- break;
- }
- return ZX_ERR_NOT_SUPPORTED;
-}
-
-static void hidctl_release(void* ctx) {
- hidctl_instance_t* inst = ctx;
- hid_release_device(&inst->hiddev);
- if (inst->hid_report_desc) {
- free(inst->hid_report_desc);
- device_remove(&inst->hiddev.dev);
- }
- free(inst);
-}
-
-zx_protocol_device_t hidctl_instance_proto = {
- .read = hidctl_read,
- .write = hidctl_write,
- .ioctl = hidctl_ioctl,
- .release = hidctl_release,
-};
-
-static zx_status_t hidctl_open(void* ctx, zx_device_t** dev_out, uint32_t flags) {
- hidctl_root_t* root = ctx;
- hidctl_instance_t* inst = calloc(1, sizeof(hidctl_instance_t));
- if (inst == NULL) {
- return ZX_ERR_NO_MEMORY;
- }
- inst->parent = root->zxdev;
-
- zx_status_t status;
- if ((status = device_create("hidctl-inst", inst, &hidctl_instance_proto, &_driver_hidctl,
- &inst->zxdev)) < 0) {
- free(inst);
- return status;
- }
-
- status = device_add_instance(inst->zxdev, root->zxdev);
- if (status != ZX_OK) {
- printf("hidctl: could not open instance: %d\n", status);
- device_destroy(inst->zxdev);
- free(inst);
- return status;
- }
- *dev_out = inst->zxdev;
- return ZX_OK;
-}
-
-static void hidctl_root_release(void* ctx) {
- hidctl_root_t* root = ctx;
- device_destroy(root->zxdev);
- free(root);
-}
-
-static zx_protocol_device_t hidctl_device_proto = {
- .open = hidctl_open,
- .release = hidctl_root_release,
-};
-
-static zx_status_t hidctl_bind(void* ctx, zx_device_t* parent, void** cookie) {
- hidctl_root_t* root = calloc(1, sizeof(hidctl_root_t));
- if (!root) {
- return ZX_ERR_NO_MEMORY;
- }
-
- zx_status_t status;
- if ((status = device_create("hidctl", root, &hidctl_device_proto, driver, &root->zxdev)) < 0) {
- free(root);
- return status;
- }
- if ((status = device_add(root->zxdev, parent)) < 0) {
- device_destroy(root->zxdev);
- free(root);
- return status;
- }
-
- return ZX_OK;
-}
-
-static zx_driver_ops_t hidctl_driver_ops = {
- .version = DRIVER_OPS_VERSION,
- .bind = hidctl_bind,
-};
-
-ZIRCON_DRIVER_BEGIN(hidctl, hidctl_driver_ops, "zircon", "0.1", 1)
- BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_MISC_PARENT),
-ZIRCON_DRIVER_END(hidctl)
diff --git a/system/dev/input/hidctl/hidctl.cpp b/system/dev/input/hidctl/hidctl.cpp
new file mode 100644
index 0000000..ca80a82
--- /dev/null
+++ b/system/dev/input/hidctl/hidctl.cpp
@@ -0,0 +1,292 @@
+// 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.
+
+#include "hidctl.h"
+
+#include <ddk/debug.h>
+#include <zircon/compiler.h>
+#include <fbl/auto_lock.h>
+#include <fbl/type_support.h>
+#include <pretty/hexdump.h>
+
+#include <stdio.h>
+#include <string.h>
+
+namespace hidctl {
+
+HidCtl::HidCtl(zx_device_t* device) : ddk::Device<HidCtl, ddk::Ioctlable>(device) {}
+
+void HidCtl::DdkRelease() {
+ delete this;
+}
+
+zx_status_t HidCtl::DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf,
+ size_t out_len, size_t* out_actual) {
+ switch (op) {
+ case IOCTL_HIDCTL_CONFIG: {
+ if (in_buf == nullptr || in_len < sizeof(hid_ioctl_config_t) ||
+ out_buf == nullptr || out_len != sizeof(zx_handle_t) || out_actual == nullptr) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+
+ auto config = static_cast<const hid_ioctl_config*>(in_buf);
+ if (in_len != sizeof(hid_ioctl_config_t) + config->rpt_desc_len) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+
+ if (config->dev_class > HID_DEV_CLASS_LAST) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+
+
+ zx::socket local, remote;
+ zx_status_t status = zx::socket::create(ZX_SOCKET_DATAGRAM, &local, &remote);
+ if (status != ZX_OK) {
+ return status;
+ }
+
+
+ auto hiddev = fbl::unique_ptr<hidctl::HidDevice>(
+ new hidctl::HidDevice(zxdev(), config, fbl::move(local)));
+
+ status = hiddev->DdkAdd("hidctl-dev");
+ if (status != ZX_OK) {
+ dprintf(ERROR, "hidctl: could not add hid device: %d\n", status);
+ hiddev->Shutdown();
+ } else {
+ // devmgr owns the memory until release is called
+ hiddev.release();
+
+ auto out = static_cast<zx_handle_t*>(out_buf);
+ *out = remote.release();
+ *out_actual = sizeof(zx_handle_t);
+ dprintf(INFO, "hidctl: created hid device\n");
+ }
+ return status;
+ }
+ default:
+ return ZX_ERR_NOT_SUPPORTED;
+ }
+}
+
+int hid_device_thread(void* arg) {
+ HidDevice* device = reinterpret_cast<HidDevice*>(arg);
+ return device->Thread();
+}
+
+#define HID_SHUTDOWN ZX_USER_SIGNAL_7
+
+HidDevice::HidDevice(zx_device_t* device, const hid_ioctl_config* config, zx::socket data)
+ : ddk::Device<HidDevice, ddk::Unbindable>(device),
+ boot_device_(config->boot_device),
+ dev_class_(config->dev_class),
+ report_desc_(new uint8_t[config->rpt_desc_len]),
+ report_desc_len_(config->rpt_desc_len),
+ data_(fbl::move(data)) {
+ ZX_DEBUG_ASSERT(data_.is_valid());
+ memcpy(report_desc_.get(), config->rpt_desc, report_desc_len_);
+ int ret = thrd_create_with_name(&thread_, hid_device_thread, reinterpret_cast<void*>(this),
+ "hidctl-thread");
+ ZX_DEBUG_ASSERT(ret == thrd_success);
+}
+
+void HidDevice::DdkRelease() {
+ dprintf(TRACE, "hidctl: DdkRelease\n");
+ // Only the thread will call DdkRemove() when the loop exits. This detachs the thread before it
+ // exits, so no need to join.
+ delete this;
+}
+
+void HidDevice::DdkUnbind() {
+ dprintf(TRACE, "hidctl: DdkUnbind\n");
+ Shutdown();
+ // The thread will call DdkRemove when it exits the loop.
+}
+
+zx_status_t HidDevice::HidBusQuery(uint32_t options, hid_info_t* info) {
+ dprintf(TRACE, "hidctl: query\n");
+
+ info->dev_num = 0;
+ info->dev_class = dev_class_;
+ info->boot_device = boot_device_;
+ return ZX_OK;
+}
+
+zx_status_t HidDevice::HidBusStart(ddk::HidBusIfcProxy proxy) {
+ dprintf(TRACE, "hidctl: start\n");
+
+ fbl::AutoLock lock(&lock_);
+ if (proxy_.is_valid()) {
+ return ZX_ERR_ALREADY_BOUND;
+ }
+ proxy_ = proxy;
+ return ZX_OK;
+}
+
+void HidDevice::HidBusStop() {
+ dprintf(TRACE, "hidctl: stop\n");
+
+ fbl::AutoLock lock(&lock_);
+ proxy_.clear();
+}
+
+zx_status_t HidDevice::HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len) {
+ dprintf(TRACE, "hidctl: get descriptor %u\n", desc_type);
+
+ if (data == nullptr || len == nullptr) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+
+ if (desc_type != HID_DESC_TYPE_REPORT) {
+ return ZX_ERR_NOT_FOUND;
+ }
+
+ *data = malloc(report_desc_len_);
+ if (*data == nullptr) {
+ return ZX_ERR_NO_MEMORY;
+ }
+ *len = report_desc_len_;
+ memcpy(*data, report_desc_.get(), report_desc_len_);
+ return ZX_OK;
+}
+
+zx_status_t HidDevice::HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len,
+ size_t* out_len) {
+ dprintf(TRACE, "hidctl: get report type=%u id=%u\n", rpt_type, rpt_id);
+
+ if (out_len == nullptr) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+
+ // TODO: send get report message over socket
+ return ZX_ERR_NOT_SUPPORTED;
+}
+
+zx_status_t HidDevice::HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len) {
+ dprintf(TRACE, "hidctl: set report type=%u id=%u\n", rpt_type, rpt_id);
+
+ // TODO: send set report message over socket
+ return ZX_ERR_NOT_SUPPORTED;
+}
+
+zx_status_t HidDevice::HidBusGetIdle(uint8_t rpt_id, uint8_t* duration) {
+ dprintf(TRACE, "hidctl: get idle\n");
+
+ // TODO: send get idle message over socket
+ return ZX_ERR_NOT_SUPPORTED;
+}
+
+zx_status_t HidDevice::HidBusSetIdle(uint8_t rpt_id, uint8_t duration) {
+ dprintf(TRACE, "hidctl: set idle\n");
+
+ // TODO: send set idle message over socket
+ return ZX_OK;
+}
+
+zx_status_t HidDevice::HidBusGetProtocol(uint8_t* protocol) {
+ dprintf(TRACE, "hidctl: get protocol\n");
+
+ // TODO: send get protocol message over socket
+ return ZX_ERR_NOT_SUPPORTED;
+}
+
+zx_status_t HidDevice::HidBusSetProtocol(uint8_t protocol) {
+ dprintf(TRACE, "hidctl: set protocol\n");
+
+ // TODO: send set protocol message over socket
+ return ZX_OK;
+}
+
+int HidDevice::Thread() {
+ dprintf(TRACE, "hidctl: starting main thread\n");
+ zx_signals_t pending;
+ fbl::unique_ptr<uint8_t[]> buf(new uint8_t[mtu_]);
+
+ zx_status_t status = ZX_OK;
+ const zx_signals_t wait = ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED | HID_SHUTDOWN;
+ while (true) {
+ status = data_.wait_one(wait, ZX_TIME_INFINITE, &pending);
+ if (status != ZX_OK) {
+ dprintf(ERROR, "hidctl: error waiting on data: %d\n", status);
+ break;
+ }
+
+ if (pending & ZX_SOCKET_READABLE) {
+ status = Recv(buf.get(), mtu_);
+ if (status != ZX_OK) {
+ break;
+ }
+ }
+ if (pending & ZX_SOCKET_PEER_CLOSED) {
+ dprintf(TRACE, "hidctl: socket closed (peer)\n");
+ break;
+ }
+ if (pending & HID_SHUTDOWN) {
+ dprintf(TRACE, "hidctl: socket closed (self)\n");
+ break;
+ }
+ }
+
+ dprintf(INFO, "hidctl: device destroyed\n");
+ {
+ fbl::AutoLock lock(&lock_);
+ data_.reset();
+ thrd_detach(thread_);
+ }
+ DdkRemove();
+
+ return static_cast<int>(status);
+}
+
+void HidDevice::Shutdown() {
+ fbl::AutoLock lock(&lock_);
+ if (data_.is_valid()) {
+ // Prevent further writes to the socket
+ zx_status_t status = data_.write(ZX_SOCKET_SHUTDOWN_READ, nullptr, 0, nullptr);
+ ZX_DEBUG_ASSERT(status == ZX_OK);
+ // Signal the thread to shutdown
+ status = data_.signal(0, HID_SHUTDOWN);
+ ZX_DEBUG_ASSERT(status == ZX_OK);
+ }
+}
+
+zx_status_t HidDevice::Recv(uint8_t* buffer, uint32_t capacity) {
+ size_t actual = 0;
+ zx_status_t status = ZX_OK;
+ // Read all the datagrams out of the socket.
+ while (status == ZX_OK) {
+ status = data_.read(0u, buffer, capacity, &actual);
+ if (status == ZX_ERR_SHOULD_WAIT || status == ZX_ERR_PEER_CLOSED) {
+ break;
+ }
+ if (status != ZX_OK) {
+ dprintf(ERROR, "hidctl: error reading data: %d\n", status);
+ return status;
+ }
+
+ fbl::AutoLock lock(&lock_);
+ if (unlikely(driver_get_log_flags() & DDK_LOG_TRACE)) {
+ dprintf(TRACE, "hidctl: received %zu bytes\n", actual);
+ hexdump8_ex(buffer, actual, 0);
+ }
+ if (proxy_.is_valid()) {
+ proxy_.IoQueue(buffer, actual);
+ }
+ }
+ return ZX_OK;
+}
+
+} // namespace hidctl
+
+extern "C" zx_status_t hidctl_bind(void* ctx, zx_device_t* device, void** cookie) {
+ auto dev = fbl::unique_ptr<hidctl::HidCtl>(new hidctl::HidCtl(device));
+ zx_status_t status = dev->DdkAdd("hidctl");
+ if (status != ZX_OK) {
+ dprintf(ERROR, "%s: could not add device: %d\n", __func__, status);
+ } else {
+ // devmgr owns the memory now
+ dev.release();
+ }
+ return status;
+}
diff --git a/system/dev/input/hidctl/hidctl.h b/system/dev/input/hidctl/hidctl.h
new file mode 100644
index 0000000..aa01ba3
--- /dev/null
+++ b/system/dev/input/hidctl/hidctl.h
@@ -0,0 +1,67 @@
+// 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 <ddk/device.h>
+#include <ddktl/device.h>
+#include <ddktl/protocol/hidbus.h>
+#include <fbl/mutex.h>
+#include <fbl/unique_ptr.h>
+#include <threads.h>
+#include <zircon/compiler.h>
+#include <zircon/device/hidctl.h>
+#include <zircon/types.h>
+#include <zx/socket.h>
+
+namespace hidctl {
+
+class HidCtl : public ddk::Device<HidCtl, ddk::Ioctlable> {
+ public:
+ HidCtl(zx_device_t* device);
+
+ void DdkRelease();
+ zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf,
+ size_t out_len, size_t* out_actual);
+};
+
+class HidDevice : public ddk::Device<HidDevice, ddk::Unbindable>,
+ public ddk::HidBusProtocol<HidDevice> {
+ public:
+ HidDevice(zx_device_t* device, const hid_ioctl_config* config, zx::socket data);
+
+ void DdkRelease();
+ void DdkUnbind();
+
+ zx_status_t HidBusQuery(uint32_t options, hid_info_t* info);
+ zx_status_t HidBusStart(ddk::HidBusIfcProxy proxy);
+ 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, 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);
+
+ int Thread();
+ void Shutdown();
+
+ private:
+ zx_status_t Recv(uint8_t* buffer, uint32_t capacity);
+
+ bool boot_device_;
+ uint8_t dev_class_;
+ fbl::unique_ptr<uint8_t[]> report_desc_;
+ size_t report_desc_len_ = 0;
+ uint32_t mtu_ = 256; // TODO: set this based on report_desc_
+
+ fbl::Mutex lock_;
+ ddk::HidBusIfcProxy proxy_ __TA_GUARDED(lock_);
+ zx::socket data_;
+ thrd_t thread_;
+};
+
+} // namespace hidctl
diff --git a/system/dev/input/hidctl/rules.mk b/system/dev/input/hidctl/rules.mk
index e8c22b4..83691c7 100644
--- a/system/dev/input/hidctl/rules.mk
+++ b/system/dev/input/hidctl/rules.mk
@@ -2,26 +2,27 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-################################################################################
-#
-# TODO(tkilbourn)
-# This driver is disabled until we can update it to use the new
-# ZX_PROTOCOL_HIDBUS protocol, which requires rationalizing all of the device
-# lifecycle events.
-#
-################################################################################
+LOCAL_DIR := $(GET_LOCAL_DIR)
-#LOCAL_DIR := $(GET_LOCAL_DIR)
-#
-#MODULE := $(LOCAL_DIR)
-#
-#MODULE_TYPE := driver
-#
-#MODULE_SRCS := $(LOCAL_DIR)/hidctl.c
-#
-#MODULE_STATIC_LIBS := system/ulib/ddk
-#
-#MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
-#
-#include make/module.mk
+MODULE := $(LOCAL_DIR)
+MODULE_TYPE := driver
+
+MODULE_SRCS := \
+ $(LOCAL_DIR)/binding.c \
+ $(LOCAL_DIR)/hidctl.cpp \
+
+MODULE_STATIC_LIBS := \
+ system/ulib/ddk \
+ system/ulib/ddktl \
+ system/ulib/zx \
+ system/ulib/zxcpp \
+ system/ulib/fbl \
+ system/ulib/pretty \
+
+MODULE_LIBS := \
+ system/ulib/driver \
+ system/ulib/zircon \
+ system/ulib/c
+
+include make/module.mk
diff --git a/system/public/zircon/device/hidctl.h b/system/public/zircon/device/hidctl.h
index a5a4ed6..230f1fc 100644
--- a/system/public/zircon/device/hidctl.h
+++ b/system/public/zircon/device/hidctl.h
@@ -9,9 +9,11 @@
#include <stdint.h>
#include <zircon/device/ioctl.h>
#include <zircon/device/ioctl-wrapper.h>
+#include <zircon/types.h>
-#define IOCTL_HID_CTL_CONFIG \
- IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_HID, 0)
+// Returns a socket that can be used to send input reports and receive output reports.
+#define IOCTL_HIDCTL_CONFIG \
+ IOCTL(IOCTL_KIND_GET_HANDLE, IOCTL_FAMILY_HID, 0)
typedef struct hid_ioctl_config {
uint8_t dev_num;
@@ -21,5 +23,5 @@
uint8_t rpt_desc[];
} hid_ioctl_config_t;
-// ssize_t ioctl_hid_ctl_config(int fd, const hid_ioctl_config_t* in, size_t in_len);
-IOCTL_WRAPPER_VARIN(ioctl_hid_ctl_config, IOCTL_HID_CTL_CONFIG, hid_ioctl_config_t);
+// ssize_t ioctl_hidctl_config(int fd, const hid_ioctl_config_t* in, size_t in_len, zx_handle_t* out);
+IOCTL_WRAPPER_VARIN_OUT(ioctl_hidctl_config, IOCTL_HIDCTL_CONFIG, hid_ioctl_config_t, zx_handle_t);