Files
OpenCellular/common/gpio_commands.c
Bill Richardson 8c4421759d Cr50: Mark several console commands as safe
Even when CONFIG_RESTRICTED_CONSOLE_COMMANDS is enabled, there
are many commands that can't do anything dangerous. This marks
some of those commands as safe to use, even when restrictions are
enforced.

I'm only marking commands that are used by the Cr50, since that's
the only board that has restrictions.

BUG=chrome-os-partner:55322
BRANCH=none
TEST=make buildall, test on Cr50 hardware

Change-Id: I6289d332830175b6adcb6b20cb4c21d01d27a25e
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/376188
Reviewed-by: Randall Spangler <rspangler@chromium.org>
2016-08-31 17:20:26 +00:00

273 lines
6.2 KiB
C

/* Copyright (c) 2013 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.
*/
/* GPIO common functionality for Chrome EC */
#include "common.h"
#include "console.h"
#include "gpio.h"
#include "host_command.h"
#include "system.h"
#include "util.h"
static uint8_t last_val[(GPIO_COUNT + 7) / 8];
/**
* Find a GPIO signal by name.
*
* @param name Signal name to find
*
* @return the signal index, or GPIO_COUNT if no match.
*/
static enum gpio_signal find_signal_by_name(const char *name)
{
int i;
if (!name || !*name)
return GPIO_COUNT;
for (i = 0; i < GPIO_COUNT; i++)
if (gpio_is_implemented(i) &&
!strcasecmp(name, gpio_get_name(i)))
return i;
return GPIO_COUNT;
}
/**
* Update last_val
*
* @param i Index of last_val[] to update
* @param v New value for last_val[i]
*
* @return 1 if last_val[i] was updated, 0 if last_val[i]==v.
*/
static int last_val_changed(int i, int v)
{
if (v && !(last_val[i / 8] & (1 << (i % 8)))) {
last_val[i / 8] |= 1 << (i % 8);
return 1;
} else if (!v && last_val[i / 8] & (1 << (i % 8))) {
last_val[i / 8] &= ~(1 << (i % 8));
return 1;
} else {
return 0;
}
}
static enum ec_error_list set(const char *name, int value)
{
enum gpio_signal signal = find_signal_by_name(name);
if (signal == GPIO_COUNT)
return EC_ERROR_INVAL;
if (!gpio_is_implemented(signal))
return EC_ERROR_INVAL;
if (!(gpio_get_default_flags(signal) & GPIO_OUTPUT))
return EC_ERROR_INVAL;
gpio_set_level(signal, value);
return EC_SUCCESS;
}
/*****************************************************************************/
/* Console commands */
static void print_gpio_info(int gpio)
{
int changed, v, flags;
if (!gpio_is_implemented(gpio))
return; /* Skip unsupported signals */
v = gpio_get_level(gpio);
#ifdef CONFIG_CMD_GPIO_EXTENDED
flags = gpio_get_flags(gpio);
#else
flags = 0;
#endif
changed = last_val_changed(gpio, v);
ccprintf(" %d%c %s%s%s%s%s%s%s%s%s%s\n", v, (changed ? '*' : ' '),
(flags & GPIO_INPUT ? "I " : ""),
(flags & GPIO_OUTPUT ? "O " : ""),
(flags & GPIO_LOW ? "L " : ""),
(flags & GPIO_HIGH ? "H " : ""),
(flags & GPIO_ANALOG ? "A " : ""),
(flags & GPIO_OPEN_DRAIN ? "ODR " : ""),
(flags & GPIO_PULL_UP ? "PU " : ""),
(flags & GPIO_PULL_DOWN ? "PD " : ""),
(flags & GPIO_ALTERNATE ? "ALT " : ""),
gpio_get_name(gpio));
/* Flush console to avoid truncating output */
cflush();
}
static int command_gpio_get(int argc, char **argv)
{
int i;
/* If a signal is specified, print only that one */
if (argc == 2) {
i = find_signal_by_name(argv[1]);
if (i == GPIO_COUNT)
return EC_ERROR_PARAM1;
print_gpio_info(i);
return EC_SUCCESS;
}
/* Otherwise print them all */
for (i = 0; i < GPIO_COUNT; i++) {
if (!gpio_is_implemented(i))
continue; /* Skip unsupported signals */
print_gpio_info(i);
}
return EC_SUCCESS;
}
DECLARE_SAFE_CONSOLE_COMMAND(gpioget, command_gpio_get,
"[name]",
"Read GPIO value(s)");
static int command_gpio_set(int argc, char **argv)
{
#ifdef CONFIG_CMD_GPIO_EXTENDED
int gpio;
int flags = 0;
int af = -1;
char *e;
if (argc < 3)
return EC_ERROR_PARAM_COUNT;
gpio = find_signal_by_name(argv[1]);
if (gpio == GPIO_COUNT)
return EC_ERROR_PARAM1;
if (strcasecmp(argv[2], "IN") == 0)
flags = GPIO_INPUT;
else if (strcasecmp(argv[2], "1") == 0)
flags = GPIO_OUT_HIGH;
else if (strcasecmp(argv[2], "0") == 0)
flags = GPIO_OUT_LOW;
else if (strcasecmp(argv[2], "A") == 0)
flags = GPIO_ANALOG;
else if (strcasecmp(argv[2], "ALT") == 0) {
if (argc >= 4) {
af = strtoi(argv[3], &e, 0);
if (*e || af < 0 || af > 5)
return EC_ERROR_PARAM2;
}
flags = GPIO_ALTERNATE;
} else
return EC_ERROR_PARAM2;
/* Update alt function if requested. */
if (af >= 0) {
const struct gpio_info *g = gpio_list + gpio;
gpio_set_alternate_function(g->port, g->mask, af);
}
/* Update GPIO flags. */
gpio_set_flags(gpio, flags);
#else
char *e;
int v;
if (argc < 3)
return EC_ERROR_PARAM_COUNT;
v = strtoi(argv[2], &e, 0);
if (*e)
return EC_ERROR_PARAM2;
if (set(argv[1], v) != EC_SUCCESS)
return EC_ERROR_PARAM1;
#endif
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(gpioset, command_gpio_set,
#ifdef CONFIG_CMD_GPIO_EXTENDED
"name <0 | 1 | IN | A | ALT [func]>",
#else
"name <0 | 1>",
#endif
"Set a GPIO");
/*****************************************************************************/
/* Host commands */
static int gpio_command_get(struct host_cmd_handler_args *args)
{
const struct ec_params_gpio_get_v1 *p_v1 = args->params;
struct ec_response_gpio_get_v1 *r_v1 = args->response;
int i, len;
if (args->version == 0) {
const struct ec_params_gpio_get *p = args->params;
struct ec_response_gpio_get *r = args->response;
i = find_signal_by_name(p->name);
if (i == GPIO_COUNT)
return EC_RES_ERROR;
r->val = gpio_get_level(i);
args->response_size = sizeof(struct ec_response_gpio_get);
return EC_RES_SUCCESS;
}
switch (p_v1->subcmd) {
case EC_GPIO_GET_BY_NAME:
i = find_signal_by_name(p_v1->get_value_by_name.name);
if (i == GPIO_COUNT)
return EC_RES_ERROR;
r_v1->get_value_by_name.val = gpio_get_level(i);
args->response_size = sizeof(r_v1->get_value_by_name);
break;
case EC_GPIO_GET_COUNT:
r_v1->get_count.val = GPIO_COUNT;
args->response_size = sizeof(r_v1->get_count);
break;
case EC_GPIO_GET_INFO:
if (p_v1->get_info.index >= GPIO_COUNT)
return EC_RES_ERROR;
i = p_v1->get_info.index;
len = strlen(gpio_get_name(i));
memcpy(r_v1->get_info.name, gpio_get_name(i), len+1);
r_v1->get_info.val = gpio_get_level(i);
r_v1->get_info.flags = gpio_get_default_flags(i);
args->response_size = sizeof(r_v1->get_info);
break;
default:
return EC_RES_INVALID_PARAM;
}
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_GPIO_GET, gpio_command_get,
EC_VER_MASK(0) | EC_VER_MASK(1));
static int gpio_command_set(struct host_cmd_handler_args *args)
{
const struct ec_params_gpio_set *p = args->params;
if (system_is_locked())
return EC_RES_ACCESS_DENIED;
if (set(p->name, p->val) != EC_SUCCESS)
return EC_RES_ERROR;
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_GPIO_SET, gpio_command_set, EC_VER_MASK(0));