Messages in this thread Patch in this message | | | Date | Fri, 14 Dec 2018 17:18:37 -0700 | Subject | [RFC PATCH 04/10] CHROMIUM: wilco_ec: Add support for raw commands in sysfs | From | Nick Crews <> |
| |
From: Duncan Laurie <dlaurie@google.com>
Add a sysfs attribute that allows sending raw commands to the EC. This is useful for development and debug but should not be enabled in a production environment.
> echo 00 f0 38 00 03 00 > /sys/bus/platform/devices/GOOG000C\:00/raw > cat /sys/bus/platform/devices/GOOG000C\:00/raw 00 37 33 38 65 64 00...
Signed-off-by: Duncan Laurie <dlaurie@google.com> Signed-off-by: Nick Crews <ncrews@google.com> ---
drivers/platform/chrome/Kconfig | 10 ++ drivers/platform/chrome/wilco_ec.h | 6 + drivers/platform/chrome/wilco_ec_mailbox.c | 6 - drivers/platform/chrome/wilco_ec_sysfs.c | 126 +++++++++++++++++++++ 4 files changed, 142 insertions(+), 6 deletions(-)
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 4168d5e6bedc..05c6d9a00395 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -61,6 +61,16 @@ config WILCO_EC To compile this driver as a module, choose M here: the module will be called wilco_ec. +config WILCO_EC_SYSFS_RAW + bool "Enable raw access to EC via sysfs" + depends on WILCO_EC + default n + help + If you say Y here, you get support for sending raw commands to + the Wilco EC via sysfs. These commands do not do any byte + manipulation and allow for testing arbitrary commands. This + interface is intended for debug only and is disabled by default. + config CROS_EC_CTL tristate diff --git a/drivers/platform/chrome/wilco_ec.h b/drivers/platform/chrome/wilco_ec.h index 699f4cf744dc..0b3dec4e2830 100644 --- a/drivers/platform/chrome/wilco_ec.h +++ b/drivers/platform/chrome/wilco_ec.h @@ -20,6 +20,12 @@ #include <linux/device.h> #include <linux/kernel.h> +/* Normal commands have a maximum 32 bytes of data */ +#define EC_MAILBOX_DATA_SIZE 32 + +/* Extended commands have 256 bytes of response data */ +#define EC_MAILBOX_DATA_SIZE_EXTENDED 256 + #define WILCO_EC_FLAG_NO_RESPONSE BIT(0) /* EC does not respond */ #define WILCO_EC_FLAG_EXTENDED_DATA BIT(1) /* EC returns 256 data bytes */ #define WILCO_EC_FLAG_RAW_REQUEST BIT(2) /* Do not trim request data */ diff --git a/drivers/platform/chrome/wilco_ec_mailbox.c b/drivers/platform/chrome/wilco_ec_mailbox.c index 414ea0a8ad03..1cb34b7280fd 100644 --- a/drivers/platform/chrome/wilco_ec_mailbox.c +++ b/drivers/platform/chrome/wilco_ec_mailbox.c @@ -44,12 +44,6 @@ /* Version of EC protocol */ #define EC_MAILBOX_PROTO_VERSION 3 -/* Normal commands have a maximum 32 bytes of data */ -#define EC_MAILBOX_DATA_SIZE 32 - -/* Extended commands have 256 bytes of response data */ -#define EC_MAILBOX_DATA_SIZE_EXTENDED 256 - /* Number of header bytes to be counted as data bytes */ #define EC_MAILBOX_DATA_EXTRA 2 diff --git a/drivers/platform/chrome/wilco_ec_sysfs.c b/drivers/platform/chrome/wilco_ec_sysfs.c index f9ae6cef6169..eeebd4ba4a39 100644 --- a/drivers/platform/chrome/wilco_ec_sysfs.c +++ b/drivers/platform/chrome/wilco_ec_sysfs.c @@ -23,6 +23,126 @@ #define EC_INFO_SIZE 9 #define EC_COMMAND_STEALTH_MODE 0xfc +#ifdef CONFIG_WILCO_EC_SYSFS_RAW + +/* Raw data buffer, large enough to hold extended responses */ +static size_t raw_response_size; +static u8 raw_response_data[EC_MAILBOX_DATA_SIZE_EXTENDED]; + +/* + * raw: write a raw command and return the result + * + * Bytes 0-1 indicate the message type: + * 00 F0 = Execute Legacy Command + * 00 F2 = Read/Write NVRAM Property + * Byte 2 provides the command code + * Bytes 3+ consist of the data passed in the request + * + * example: read the EC info type 1: + * # echo 00 f0 38 00 01 00 > raw + * # cat raw + * 00 38 31 34 34 66 00 00 00 00 00 00 00 00 00 00 00... + */ + +static ssize_t raw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + + if (raw_response_size) { + int i; + + for (i = 0; i < raw_response_size; ++i) + count += scnprintf(buf + count, PAGE_SIZE - count, + "%02x ", raw_response_data[i]); + + count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); + + /* Only return response the first time it is read */ + raw_response_size = 0; + } + + return count; +} + +static ssize_t raw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wilco_ec_device *ec = dev_get_drvdata(dev); + struct wilco_ec_message msg; + u8 raw_request_data[EC_MAILBOX_DATA_SIZE]; + int in_offset = 0; + int out_offset = 0; + int ret; + + while (in_offset < count) { + char word_buf[EC_MAILBOX_DATA_SIZE]; + u8 byte; + int start_offset = in_offset; + int end_offset; + + /* Find the start of the byte */ + while (buf[start_offset] && isspace(buf[start_offset])) + start_offset++; + if (!buf[start_offset]) + break; + + /* Find the start of the next byte, if any */ + end_offset = start_offset; + while (buf[end_offset] && !isspace(buf[end_offset])) + end_offset++; + if (start_offset > count || end_offset > count) + break; + if (start_offset > EC_MAILBOX_DATA_SIZE || + end_offset > EC_MAILBOX_DATA_SIZE) + break; + + /* Copy to a new nul-terminated string */ + memcpy(word_buf, buf + start_offset, end_offset - start_offset); + word_buf[end_offset - start_offset] = '\0'; + + /* Convert from hex string */ + ret = kstrtou8(word_buf, 16, &byte); + if (ret) + break; + + /* Fill this byte into the request buffer */ + raw_request_data[out_offset++] = byte; + if (out_offset >= EC_MAILBOX_DATA_SIZE) + break; + + in_offset = end_offset; + } + if (out_offset == 0) + return -EINVAL; + + /* Clear response data buffer */ + memset(raw_response_data, 0, EC_MAILBOX_DATA_SIZE_EXTENDED); + + msg.type = raw_request_data[0] << 8 | raw_request_data[1]; + msg.flags = WILCO_EC_FLAG_RAW; + msg.command = raw_request_data[2]; + msg.request_data = raw_request_data + 3; + msg.request_size = out_offset - 3; + msg.response_data = raw_response_data; + msg.response_size = EC_MAILBOX_DATA_SIZE; + + /* Telemetry commands use extended response data */ + if (msg.type == WILCO_EC_MSG_TELEMETRY) { + msg.flags |= WILCO_EC_FLAG_EXTENDED_DATA; + msg.response_size = EC_MAILBOX_DATA_SIZE_EXTENDED; + } + + ret = wilco_ec_mailbox(ec, &msg); + if (ret < 0) + return ret; + raw_response_size = ret; + return count; +} + +#endif /* CONFIG_WILCO_EC_SYSFS_RAW */ + struct ec_info { u8 index; const char *label; @@ -102,10 +222,16 @@ static ssize_t stealth_mode_store(struct device *dev, static DEVICE_ATTR_RO(version); static DEVICE_ATTR_WO(stealth_mode); +#ifdef CONFIG_WILCO_EC_SYSFS_RAW +static DEVICE_ATTR_RW(raw); +#endif static struct attribute *wilco_ec_attrs[] = { &dev_attr_version.attr, &dev_attr_stealth_mode.attr, +#ifdef CONFIG_WILCO_EC_SYSFS_RAW + &dev_attr_raw.attr, +#endif NULL }; ATTRIBUTE_GROUPS(wilco_ec); -- 2.20.0.405.gbc1bbc6f85-goog
| |