diff options
Diffstat (limited to 'chip/ish/hid_subsys.c')
-rw-r--r-- | chip/ish/hid_subsys.c | 447 |
1 files changed, 0 insertions, 447 deletions
diff --git a/chip/ish/hid_subsys.c b/chip/ish/hid_subsys.c deleted file mode 100644 index bd3f331fdc..0000000000 --- a/chip/ish/hid_subsys.c +++ /dev/null @@ -1,447 +0,0 @@ -/* Copyright 2018 The Chromium OS 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 "compile_time_macros.h" -#include "console.h" -#include "heci_client.h" -#include "hid_device.h" -#include "util.h" - -#ifdef HID_SUBSYS_DEBUG -#define CPUTS(outstr) cputs(CC_LPC, outstr) -#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_LPC, format, ## args) -#else -#define CPUTS(outstr) -#define CPRINTS(format, args...) -#define CPRINTF(format, args...) -#endif - -#define __packed __attribute__((packed)) - -#define HECI_CLIENT_HID_GUID { 0x33AECD58, 0xB679, 0x4E54,\ - { 0x9B, 0xD9, 0xA0, 0x4D, 0x34, 0xF0, 0xC2, 0x26 } } - -#define HID_SUBSYS_MAX_HID_DEVICES 3 - -/* - * the following enum values and data structures with __packed are used for - * communicating with host driver and they are copied from host driver. - */ -enum { - HID_GET_HID_DESCRIPTOR = 0, - HID_GET_REPORT_DESCRIPTOR, - HID_GET_FEATURE_REPORT, - HID_SET_FEATURE_REPORT, - HID_GET_INPUT_REPORT, - HID_PUBLISH_INPUT_REPORT, - HID_PUBLISH_INPUT_REPORT_LIST, /* TODO: need to support batch report */ - - HID_HID_CLIENT_READY_CMD = 30, - HID_HID_COMMAND_MAX = 31, - - HID_DM_COMMAND_BASE, - HID_DM_ENUM_DEVICES, - HID_DM_ADD_DEVICE, - HID_COMMAND_LAST -}; - -struct hid_device_info { - uint32_t dev_id; - uint8_t dev_class; - uint16_t pid; - uint16_t vid; -} __packed; - -struct hid_enum_payload { - uint8_t num_of_hid_devices; - struct hid_device_info dev_info[0]; -} __packed; - -#define COMMAND_MASK 0x7F -#define RESPONSE_FLAG 0x80 -struct hid_msg_hdr { - uint8_t command; /* bit 7 is used to indicate "response" */ - uint8_t device_id; - uint8_t status; - uint8_t flags; - uint16_t size; -} __packed; - -struct hid_msg { - struct hid_msg_hdr hdr; - uint8_t payload[HID_SUBSYS_MAX_PAYLOAD_SIZE]; -} __packed; - -struct hid_subsys_hid_device { - struct hid_device_info info; - const struct hid_callbacks *cbs; - int can_send_hid_input; - - void *data; -}; - -struct hid_subsystem { - heci_handle_t heci_handle; - - uint32_t num_of_hid_devices; - struct hid_subsys_hid_device hid_devices[HID_SUBSYS_MAX_HID_DEVICES]; -}; - -static struct hid_subsystem hid_subsys_ctx = { - .heci_handle = HECI_INVALID_HANDLE, -}; - -#define handle_to_dev_id(_handle) ((uintptr_t)(_handle)) -#define dev_id_to_handle(_dev_id) ((hid_handle_t)(uintptr_t)(_dev_id)) - -static inline hid_handle_t device_index_to_handle(int device_index) -{ - return (hid_handle_t)(uintptr_t)(device_index + 1); -} - -static inline int is_valid_handle(hid_handle_t handle) -{ - return (uintptr_t)handle > 0 && - (uintptr_t)handle <= hid_subsys_ctx.num_of_hid_devices; -} - -static inline -struct hid_subsys_hid_device *handle_to_hid_device(hid_handle_t handle) -{ - if (!is_valid_handle(handle)) - return NULL; - - return &hid_subsys_ctx.hid_devices[(uintptr_t)handle - 1]; -} - - -hid_handle_t hid_subsys_register_device(const struct hid_device *dev_info) -{ - struct hid_subsys_hid_device *hid_device; - hid_handle_t handle; - int ret, hid_device_index; - - if (hid_subsys_ctx.num_of_hid_devices >= HID_SUBSYS_MAX_HID_DEVICES) - return HID_INVALID_HANDLE; - - hid_device_index = hid_subsys_ctx.num_of_hid_devices++; - - handle = device_index_to_handle(hid_device_index); - - hid_device = &hid_subsys_ctx.hid_devices[hid_device_index]; - - hid_device->info.dev_class = dev_info->dev_class; - hid_device->info.pid = dev_info->pid; - hid_device->info.vid = dev_info->vid; - hid_device->info.dev_id = handle_to_dev_id(handle); - - hid_device->cbs = dev_info->cbs; - - if (dev_info->cbs->initialize) { - ret = dev_info->cbs->initialize(handle); - if (ret) { - CPRINTF("initialize error %d\n", ret); - hid_subsys_ctx.num_of_hid_devices--; - return HID_INVALID_HANDLE; - } - } - - return handle; -} - -int hid_subsys_send_input_report(const hid_handle_t handle, uint8_t *buf, - const size_t buf_size) -{ - struct hid_subsys_hid_device *hid_device; - struct hid_msg_hdr hid_msg_hdr = {0}; - struct heci_msg_item msg_item[2]; - struct heci_msg_list msg_list; - - hid_device = handle_to_hid_device(handle); - if (!hid_device) - return -EC_ERROR_INVAL; - - if (buf_size > HID_SUBSYS_MAX_PAYLOAD_SIZE) - return -EC_ERROR_OVERFLOW; - - if (hid_subsys_ctx.heci_handle == HECI_INVALID_HANDLE) - return -HID_SUBSYS_ERR_NOT_READY; - - if (!hid_device->can_send_hid_input) - return -HID_SUBSYS_ERR_NOT_READY; - - hid_msg_hdr.command = HID_PUBLISH_INPUT_REPORT; - hid_msg_hdr.device_id = hid_device->info.dev_id; - hid_msg_hdr.size = buf_size; - - msg_item[0].size = sizeof(hid_msg_hdr); - msg_item[0].buf = (uint8_t *)&hid_msg_hdr; - - msg_item[1].size = buf_size; - msg_item[1].buf = buf; - - msg_list.num_of_items = 2; - msg_list.items[0] = &msg_item[0]; - msg_list.items[1] = &msg_item[1]; - - heci_send_msgs(hid_subsys_ctx.heci_handle, &msg_list); - - return 0; -} - -int hid_subsys_set_device_data(const hid_handle_t handle, void *data) -{ - struct hid_subsys_hid_device *hid_device; - - hid_device = handle_to_hid_device(handle); - if (!hid_device) - return -EC_ERROR_INVAL; - - hid_device->data = data; - - return 0; -} - -void *hid_subsys_get_device_data(const hid_handle_t handle) -{ - struct hid_subsys_hid_device *hid_device; - - hid_device = handle_to_hid_device(handle); - if (!hid_device) - return NULL; - - return hid_device->data; -} - -static int handle_hid_device_msg(struct hid_msg *hid_msg) -{ - int ret = 0, payload_size, buf_size; - uint8_t *payload; - struct hid_subsys_hid_device *hid_dev; - const struct hid_callbacks *cbs; - hid_handle_t handle; - - handle = dev_id_to_handle(hid_msg->hdr.device_id); - hid_dev = handle_to_hid_device(handle); - - if (!hid_dev) { - /* - * use HID_HID_COMMAND_MAX as error message. - * host driver will reset ISH. - */ - hid_msg->hdr.size = 0; - hid_msg->hdr.status = 0; - hid_msg->hdr.command |= RESPONSE_FLAG | HID_HID_COMMAND_MAX; - hid_msg->hdr.flags = 0; - - heci_send_msg(hid_subsys_ctx.heci_handle, (uint8_t *)hid_msg, - sizeof(hid_msg->hdr)); - - return 0; - } - - cbs = hid_dev->cbs; - - payload = hid_msg->payload; - payload_size = hid_msg->hdr.size; /* input data */ - buf_size = sizeof(hid_msg->payload); /* buffer to be written by cb */ - - /* - * re-use hid_msg from host for reply. - */ - switch (hid_msg->hdr.command & COMMAND_MASK) { - case HID_GET_HID_DESCRIPTOR: - if (cbs->get_hid_descriptor) - ret = cbs->get_hid_descriptor(handle, payload, - buf_size); - - break; - case HID_GET_REPORT_DESCRIPTOR: - if (cbs->get_report_descriptor) - ret = cbs->get_report_descriptor(handle, payload, - buf_size); - - hid_dev->can_send_hid_input = 1; - - break; - - case HID_GET_FEATURE_REPORT: - if (cbs->get_feature_report) - ret = cbs->get_feature_report(handle, payload[0], - payload, buf_size); - - break; - - case HID_SET_FEATURE_REPORT: - if (cbs->set_feature_report) { - ret = cbs->set_feature_report(handle, - payload[0], - payload, - payload_size); - /* - * if no error, reply only with the report id. - * re-use the first byte of payload - * from host that has report id - */ - if (ret >= 0) - ret = sizeof(uint8_t); - } - - break; - case HID_GET_INPUT_REPORT: - if (cbs->get_input_report) - ret = cbs->get_input_report(handle, payload[0], - payload, buf_size); - - break; - - default: - CPRINTF("invalid hid command %d, ignoring request\n", - hid_msg->hdr.command & COMMAND_MASK); - ret = -1; /* send error */ - } - - if (ret > 0) { - hid_msg->hdr.size = ret; - hid_msg->hdr.status = 0; - } else { /* error in callback */ - /* - * Note : errors of HID device should be transferred - * through their HID formatted data. - */ - hid_msg->hdr.size = 0; - hid_msg->hdr.status = -ret; - } - - hid_msg->hdr.command |= RESPONSE_FLAG; - hid_msg->hdr.flags = 0; - - heci_send_msg(hid_subsys_ctx.heci_handle, (uint8_t *)hid_msg, - sizeof(hid_msg->hdr) + hid_msg->hdr.size); - - return 0; -} - -static int handle_hid_subsys_msg(struct hid_msg *hid_msg) -{ - int size = 0, i; - struct hid_enum_payload *enum_payload; - - switch (hid_msg->hdr.command & COMMAND_MASK) { - case HID_DM_ENUM_DEVICES: - enum_payload = (struct hid_enum_payload *)hid_msg->payload; - - for (i = 0; i < hid_subsys_ctx.num_of_hid_devices; i++) { - enum_payload->dev_info[i] = - hid_subsys_ctx.hid_devices[i].info; - } - - enum_payload->num_of_hid_devices = - hid_subsys_ctx.num_of_hid_devices; - - /* reply payload size */ - size = sizeof(enum_payload->num_of_hid_devices); - size += enum_payload->num_of_hid_devices * - sizeof(enum_payload->dev_info[0]); - - break; - - default: - CPRINTF("invalid hid command %d, ignoring request\n", - hid_msg->hdr.command & COMMAND_MASK); - size = -1; /* send error */ - } - - if (size > 0) { - hid_msg->hdr.size = size; - hid_msg->hdr.status = 0; - } else { /* error in callback */ - hid_msg->hdr.size = 0; - hid_msg->hdr.status = -size; - } - - hid_msg->hdr.command |= RESPONSE_FLAG; - hid_msg->hdr.flags = 0; - - heci_send_msg(hid_subsys_ctx.heci_handle, (uint8_t *)hid_msg, - sizeof(hid_msg->hdr) + hid_msg->hdr.size); - - return 0; -} - -static void hid_subsys_new_msg_received(const heci_handle_t handle, - uint8_t *msg, const size_t msg_size) -{ - struct hid_msg *hid_msg = (struct hid_msg *)msg; - - /* workaround, since Host driver doesn't set size properly */ - if (hid_msg->hdr.size == 0 && msg_size > sizeof(hid_msg->hdr)) - hid_msg->hdr.size = msg_size - sizeof(hid_msg->hdr); - - if (hid_msg->hdr.size > HID_SUBSYS_MAX_PAYLOAD_SIZE) { - CPRINTF("too big payload size : %d. discard heci msg\n", - hid_msg->hdr); - return; /* invalid hdr. discard */ - } - - if (hid_msg->hdr.device_id) - handle_hid_device_msg(hid_msg); - else - handle_hid_subsys_msg(hid_msg); -} - -static int hid_subsys_initialize(const heci_handle_t heci_handle) -{ - hid_subsys_ctx.heci_handle = heci_handle; - - return 0; -} - -/* return zero if resume request handled successfully */ -static int hid_subsys_resume(const heci_handle_t heci_handle) -{ - int i, ret = 0; - - for (i = 0; i < hid_subsys_ctx.num_of_hid_devices; i++) { - if (hid_subsys_ctx.hid_devices[i].cbs->resume) - ret |= hid_subsys_ctx.hid_devices[i].cbs->resume( - device_index_to_handle(i)); - } - - return ret; -} - -/* return zero if suspend request handled successfully */ -static int hid_subsys_suspend(const heci_handle_t heci_handle) -{ - int i, ret = 0; - - for (i = hid_subsys_ctx.num_of_hid_devices - 1; i >= 0; i--) { - if (hid_subsys_ctx.hid_devices[i].cbs->suspend) - ret |= hid_subsys_ctx.hid_devices[i].cbs->suspend( - device_index_to_handle(i)); - } - - return ret; -} - -static const struct heci_client_callbacks hid_subsys_heci_cbs = { - .initialize = hid_subsys_initialize, - .new_msg_received = hid_subsys_new_msg_received, - .suspend = hid_subsys_suspend, - .resume = hid_subsys_resume, -}; - -static const struct heci_client hid_subsys_heci_client = { - .protocol_id = HECI_CLIENT_HID_GUID, - .max_msg_size = HECI_MAX_MSG_SIZE, - .protocol_ver = 1, - .max_n_of_connections = 1, - - .cbs = &hid_subsys_heci_cbs, -}; - -HECI_CLIENT_ENTRY(hid_subsys_heci_client); |