blob: 4e2f9ff1f2be9616d19dc6201737098781a0ce85 [file] [log] [blame]
/* 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.
*/
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/io.h>
#include <unistd.h>
#include "battery.h"
#include "comm-host.h"
#include "compile_time_macros.h"
#include "ec_flash.h"
#include "ectool.h"
#include "lightbar.h"
#include "lock/gec_lock.h"
#include "misc_util.h"
#include "panic.h"
/* Command line options */
enum {
OPT_DEV = 1000,
OPT_INTERFACE,
};
static struct option long_opts[] = {
{"dev", 1, 0, OPT_DEV},
{"interface", 1, 0, OPT_INTERFACE},
{NULL, 0, 0, 0}
};
#define GEC_LOCK_TIMEOUT_SECS 30 /* 30 secs */
const char help_str[] =
"Commands:\n"
" extpwrcurrentlimit\n"
" Set the maximum external power current\n"
" autofanctrl <on>\n"
" Turn on automatic fan speed control.\n"
" backlight <enabled>\n"
" Enable/disable LCD backlight\n"
" battery\n"
" Prints battery info\n"
" batterycutoff [at-shutdown]\n"
" Cut off battery output power\n"
" batteryparam\n"
" Read or write board-specific battery parameter\n"
" boardversion\n"
" Prints the board version\n"
" chargecurrentlimit\n"
" Set the maximum battery charging current\n"
" chargecontrol\n"
" Force the battery to stop charging or discharge\n"
" chargestate\n"
" Handle commands related to charge state v2 (and later)\n"
" chipinfo\n"
" Prints chip info\n"
" cmdversions <cmd>\n"
" Prints supported version mask for a command number\n"
" console\n"
" Prints the last output to the EC debug console\n"
" echash [CMDS]\n"
" Various EC hash commands\n"
" eventclear <mask>\n"
" Clears EC host events flags where mask has bits set\n"
" eventclearb <mask>\n"
" Clears EC host events flags copy B where mask has bits set\n"
" eventget\n"
" Prints raw EC host event flags\n"
" eventgetb\n"
" Prints raw EC host event flags copy B\n"
" eventgetscimask\n"
" Prints SCI mask for EC host events\n"
" eventgetsmimask\n"
" Prints SMI mask for EC host events\n"
" eventgetwakemask\n"
" Prints wake mask for EC host events\n"
" eventsetscimask <mask>\n"
" Sets the SCI mask for EC host events\n"
" eventsetsmimask <mask>\n"
" Sets the SMI mask for EC host events\n"
" eventsetwakemask <mask>\n"
" Sets the wake mask for EC host events\n"
" fanduty <percent>\n"
" Forces the fan PWM to a constant duty cycle\n"
" flasherase <offset> <size>\n"
" Erases EC flash\n"
" flashinfo\n"
" Prints information on the EC flash\n"
" flashprotect [now] [enable | disable]\n"
" Prints or sets EC flash protection state\n"
" flashread <offset> <size> <outfile>\n"
" Reads from EC flash to a file\n"
" flashwrite <offset> <infile>\n"
" Writes to EC flash from a file\n"
" gpioget <GPIO name>\n"
" Get the value of GPIO signal\n"
" gpioset <GPIO name>\n"
" Set the value of GPIO signal\n"
" hangdetect <flags> <event_msec> <reboot_msec> | stop | start\n"
" Configure or start/stop the hang detect timer\n"
" hello\n"
" Checks for basic communication with EC\n"
" kbpress\n"
" Simulate key press\n"
" i2cread\n"
" Read I2C bus\n"
" i2cwrite\n"
" Write I2C bus\n"
" i2cxfer <port> <slave_addr> <read_count> [write bytes...]\n"
" Perform I2C transfer on EC's I2C bus\n"
" keyscan <beat_us> <filename>\n"
" Test low-level key scanning\n"
" led <name> <query | auto | off | <color> | <color>=<value>...>\n"
" Set the color of an LED or query brightness range\n"
" lightbar [CMDS]\n"
" Various lightbar control commands\n"
" motionsense [CMDS]\n"
" Various motion sense control commands\n"
" panicinfo\n"
" Prints saved panic info\n"
" pause_in_s5 [on|off]\n"
" Whether or not the AP should pause in S5 on shutdown\n"
" port80flood\n"
" Rapidly write bytes to port 80\n"
" port80read\n"
" Print history of port 80 write\n"
" powerinfo\n"
" Prints power-related information\n"
" protoinfo\n"
" Prints EC host protocol information\n"
" pstoreinfo\n"
" Prints information on the EC host persistent storage\n"
" pstoreread <offset> <size> <outfile>\n"
" Reads from EC host persistent storage to a file\n"
" pstorewrite <offset> <infile>\n"
" Writes to EC host persistent storage from a file\n"
" pwmgetfanrpm [<index> | all]\n"
" Prints current fan RPM\n"
" pwmgetkblight\n"
" Prints current keyboard backlight percent\n"
" pwmsetfanrpm <targetrpm>\n"
" Set target fan RPM\n"
" pwmsetkblight <percent>\n"
" Set keyboard backlight in percent\n"
" readtest <patternoffset> <size>\n"
" Reads a pattern from the EC via LPC\n"
" reboot_ec <RO|RW|cold|hibernate|disable-jump> [at-shutdown]\n"
" Reboot EC to RO or RW\n"
" rtcget\n"
" Print real-time clock\n"
" rtcset <time>\n"
" Set real-time clock\n"
" sertest\n"
" Serial output test for COM2\n"
" switches\n"
" Prints current EC switch positions\n"
" temps <sensorid>\n"
" Print temperature.\n"
" tempsinfo <sensorid>\n"
" Print temperature sensor info.\n"
" thermalget <platform-specific args>\n"
" Get the threshold temperature values from the thermal engine.\n"
" thermalset <platform-specific args>\n"
" Set the threshold temperature values for the thermal engine.\n"
" tmp006cal <tmp006_index> [<S0> <b0> <b1> <b2>]\n"
" Get/set TMP006 calibration\n"
" tmp006raw <tmp006_index>\n"
" Get raw TMP006 data\n"
" usbchargemode <port> <mode>\n"
" Set USB charging mode\n"
" usbmux <mux>\n"
" Set USB mux switch state\n"
" usbpd <port> <auto | "
"[toggle|toggle-off|sink|source] [none|usb|dp|dock]>\n"
" Control USB PD/type-C\n"
" version\n"
" Prints EC version\n"
" wireless <flags> [<mask> [<suspend_flags> <suspend_mask>]]\n"
" Enable/disable WLAN/Bluetooth radio\n"
"";
/* Note: depends on enum system_image_copy_t */
static const char * const image_names[] = {"unknown", "RO", "RW"};
/* Note: depends on enum ec_led_colors */
static const char * const led_color_names[EC_LED_COLOR_COUNT] = {
"red", "green", "blue", "yellow", "white"};
/* Note: depends on enum ec_led_id */
static const char * const led_names[EC_LED_ID_COUNT] = {
"battery", "power", "adapter"};
/* Check SBS numerical value range */
int is_battery_range(int val)
{
return (val >= 0 && val <= 65535) ? 1 : 0;
}
int parse_bool(const char *s, int *dest)
{
if (!strcasecmp(s, "off") || !strncasecmp(s, "dis", 3) ||
tolower(*s) == 'f' || tolower(*s) == 'n') {
*dest = 0;
return 1;
} else if (!strcasecmp(s, "on") || !strncasecmp(s, "ena", 3) ||
tolower(*s) == 't' || tolower(*s) == 'y') {
*dest = 1;
return 1;
} else {
return 0;
}
}
void print_help(const char *prog, int print_cmds)
{
printf("Usage: %s [--dev=n] [--interface=dev|lpc|i2c] <command> "
"[params]\n\n",
prog);
if (print_cmds)
puts(help_str);
else
printf("Use '%s help' to print a list of commands.\n", prog);
}
static uint8_t read_mapped_mem8(uint8_t offset)
{
int ret;
uint8_t val;
ret = ec_readmem(offset, sizeof(val), &val);
if (ret <= 0) {
fprintf(stderr, "failure in %s(): %d\n", __func__, ret);
exit(1);
}
return val;
}
static uint16_t read_mapped_mem16(uint8_t offset)
{
int ret;
uint16_t val;
ret = ec_readmem(offset, sizeof(val), &val);
if (ret <= 0) {
fprintf(stderr, "failure in %s(): %d\n", __func__, ret);
exit(1);
}
return val;
}
static uint32_t read_mapped_mem32(uint8_t offset)
{
int ret;
uint32_t val;
ret = ec_readmem(offset, sizeof(val), &val);
if (ret <= 0) {
fprintf(stderr, "failure in %s(): %d\n", __func__, ret);
exit(1);
}
return val;
}
static int read_mapped_string(uint8_t offset, char *buffer, int max_size)
{
int ret;
ret = ec_readmem(offset, max_size, buffer);
if (ret <= 0) {
fprintf(stderr, "failure in %s(): %d\n", __func__, ret);
exit(1);
}
return ret;
}
int cmd_hello(int argc, char *argv[])
{
struct ec_params_hello p;
struct ec_response_hello r;
int rv;
p.in_data = 0xa0b0c0d0;
rv = ec_command(EC_CMD_HELLO, 0, &p, sizeof(p), &r, sizeof(r));
if (rv < 0)
return rv;
if (r.out_data != 0xa1b2c3d4) {
fprintf(stderr, "Expected response 0x%08x, got 0x%08x\n",
0xa1b2c3d4, r.out_data);
return -1;
}
printf("EC says hello!\n");
return 0;
}
int cmd_test(int argc, char *argv[])
{
struct ec_params_test_protocol p = {
.buf = "0123456789abcdef0123456789ABCDEF"
};
struct ec_response_test_protocol r;
int rv, version = 0;
char *e;
if (argc < 3) {
fprintf(stderr, "Usage: %s result length [version]\n",
argv[0]);
return -1;
}
p.ec_result = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "invalid param (result)\n");
return -1;
}
p.ret_len = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "invalid param (length)\n");
return -1;
}
if (argc > 3) {
version = strtol(argv[3], &e, 0);
if (e && *e) {
fprintf(stderr, "invalid param (version)\n");
return -1;
}
}
rv = ec_command(EC_CMD_TEST_PROTOCOL, version,
&p, sizeof(p), &r, sizeof(r));
printf("rv = %d\n", rv);
return rv;
}
int cmd_s5(int argc, char *argv[])
{
struct ec_params_get_set_value p;
struct ec_params_get_set_value r;
int rv;
p.flags = 0;
if (argc > 1) {
p.flags |= EC_GSV_SET;
if (!parse_bool(argv[1], &p.value)) {
fprintf(stderr, "invalid arg \"%s\"\n", argv[1]);
return -1;
}
}
rv = ec_command(EC_CMD_GSV_PAUSE_IN_S5, 0,
&p, sizeof(p), &r, sizeof(r));
if (rv > 0)
printf("%s\n", r.value ? "on" : "off");
return rv < 0;
}
int cmd_cmdversions(int argc, char *argv[])
{
struct ec_params_get_cmd_versions p;
struct ec_response_get_cmd_versions r;
char *e;
int cmd;
int rv;
if (argc < 2) {
fprintf(stderr, "Usage: %s <cmd>\n", argv[0]);
return -1;
}
cmd = strtol(argv[1], &e, 0);
if ((e && *e) || cmd < 0 || cmd > 0xff) {
fprintf(stderr, "Bad command number.\n");
return -1;
}
p.cmd = cmd;
rv = ec_command(EC_CMD_GET_CMD_VERSIONS, 0, &p, sizeof(p),
&r, sizeof(r));
if (rv < 0) {
if (rv == -EC_RES_INVALID_PARAM)
printf("Command 0x%02x not supported by EC.\n", cmd);
return rv;
}
printf("Command 0x%02x supports version mask 0x%08x\n",
cmd, r.version_mask);
return 0;
}
int cmd_version(int argc, char *argv[])
{
struct ec_response_get_version r;
char *build_string = (char *)ec_inbuf;
int rv;
rv = ec_command(EC_CMD_GET_VERSION, 0, NULL, 0, &r, sizeof(r));
if (rv < 0) {
fprintf(stderr, "ERROR: EC_CMD_GET_VERSION failed: %d\n", rv);
return rv;
}
rv = ec_command(EC_CMD_GET_BUILD_INFO, 0,
NULL, 0, ec_inbuf, ec_max_insize);
if (rv < 0) {
fprintf(stderr, "ERROR: EC_CMD_GET_BUILD_INFO failed: %d\n",
rv);
return rv;
}
/* Ensure versions are null-terminated before we print them */
r.version_string_ro[sizeof(r.version_string_ro) - 1] = '\0';
r.version_string_rw[sizeof(r.version_string_rw) - 1] = '\0';
build_string[ec_max_insize - 1] = '\0';
/* Print versions */
printf("RO version: %s\n", r.version_string_ro);
printf("RW version: %s\n", r.version_string_rw);
printf("Firmware copy: %s\n",
(r.current_image < ARRAY_SIZE(image_names) ?
image_names[r.current_image] : "?"));
printf("Build info: %s\n", build_string);
return 0;
}
int cmd_read_test(int argc, char *argv[])
{
struct ec_params_read_test p;
struct ec_response_read_test r;
int offset, size;
int errors = 0;
int rv;
int i;
char *e;
char *buf;
uint32_t *b;
if (argc < 3) {
fprintf(stderr, "Usage: %s <pattern_offset> <size>\n", argv[0]);
return -1;
}
offset = strtol(argv[1], &e, 0);
size = strtol(argv[2], &e, 0);
if ((e && *e) || size <= 0 || size > 0x100000) {
fprintf(stderr, "Bad size.\n");
return -1;
}
printf("Reading %d bytes with pattern offset 0x%x...\n", size, offset);
buf = (char *)malloc(size);
if (!buf) {
fprintf(stderr, "Unable to allocate buffer.\n");
return -1;
}
/* Read data in chunks */
for (i = 0; i < size; i += sizeof(r.data)) {
p.offset = offset + i / sizeof(uint32_t);
p.size = MIN(size - i, sizeof(r.data));
rv = ec_command(EC_CMD_READ_TEST, 0, &p, sizeof(p),
&r, sizeof(r));
if (rv < 0) {
fprintf(stderr, "Read error at offset %d\n", i);
free(buf);
return rv;
}
memcpy(buf + i, r.data, p.size);
}
/* Check data */
for (i = 0, b = (uint32_t *)buf; i < size / 4; i++, b++) {
if (*b != i + offset) {
printf("Mismatch at byte offset 0x%x: "
"expected 0x%08x, got 0x%08x\n",
(int)(i * sizeof(uint32_t)), i + offset, *b);
errors++;
}
}
free(buf);
if (errors) {
printf("Found %d errors\n", errors);
return -1;
}
printf("done.\n");
return 0;
}
int cmd_reboot_ec(int argc, char *argv[])
{
struct ec_params_reboot_ec p;
int rv, i;
if (argc < 2) {
/*
* No params specified so tell the EC to reboot immediately.
* That reboots the AP as well, so unlikely we'll be around
* to see a return code from this...
*/
rv = ec_command(EC_CMD_REBOOT, 0, NULL, 0, NULL, 0);
return (rv < 0 ? rv : 0);
}
/* Parse command */
if (!strcmp(argv[1], "cancel"))
p.cmd = EC_REBOOT_CANCEL;
else if (!strcmp(argv[1], "RO"))
p.cmd = EC_REBOOT_JUMP_RO;
else if (!strcmp(argv[1], "RW") || !strcmp(argv[1], "A")) {
/*
* TODO(crosbug.com/p/11149): remove "A" once all scripts are
* updated to use "RW".
*/
p.cmd = EC_REBOOT_JUMP_RW;
} else if (!strcmp(argv[1], "cold"))
p.cmd = EC_REBOOT_COLD;
else if (!strcmp(argv[1], "disable-jump"))
p.cmd = EC_REBOOT_DISABLE_JUMP;
else if (!strcmp(argv[1], "hibernate"))
p.cmd = EC_REBOOT_HIBERNATE;
else {
fprintf(stderr, "Unknown command: %s\n", argv[1]);
return -1;
}
/* Parse flags, if any */
p.flags = 0;
for (i = 2; i < argc; i++) {
if (!strcmp(argv[i], "at-shutdown"))
p.flags |= EC_REBOOT_FLAG_ON_AP_SHUTDOWN;
else {
fprintf(stderr, "Unknown flag: %s\n", argv[i]);
return -1;
}
}
rv = ec_command(EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0);
return (rv < 0 ? rv : 0);
}
int cmd_flash_info(int argc, char *argv[])
{
struct ec_response_flash_info_1 r;
int cmdver = 1;
int rsize = sizeof(r);
int rv;
memset(&r, 0, sizeof(r));
if (!ec_cmd_version_supported(EC_CMD_FLASH_INFO, cmdver)) {
/* Fall back to version 0 command */
cmdver = 0;
rsize = sizeof(struct ec_response_flash_info);
}
rv = ec_command(EC_CMD_FLASH_INFO, cmdver, NULL, 0, &r, rsize);
if (rv < 0)
return rv;
printf("FlashSize %d\nWriteSize %d\nEraseSize %d\nProtectSize %d\n",
r.flash_size, r.write_block_size, r.erase_block_size,
r.protect_block_size);
if (cmdver >= 1) {
/* Fields added in ver.1 available */
printf("WriteIdealSize %d\nFlags 0x%x\n",
r.write_ideal_size, r.flags);
}
return 0;
}
int cmd_flash_read(int argc, char *argv[])
{
int offset, size;
int rv;
char *e;
char *buf;
if (argc < 4) {
fprintf(stderr,
"Usage: %s <offset> <size> <filename>\n", argv[0]);
return -1;
}
offset = strtol(argv[1], &e, 0);
if ((e && *e) || offset < 0 || offset > 0x100000) {
fprintf(stderr, "Bad offset.\n");
return -1;
}
size = strtol(argv[2], &e, 0);
if ((e && *e) || size <= 0 || size > 0x100000) {
fprintf(stderr, "Bad size.\n");
return -1;
}
printf("Reading %d bytes at offset %d...\n", size, offset);
buf = (char *)malloc(size);
if (!buf) {
fprintf(stderr, "Unable to allocate buffer.\n");
return -1;
}
/* Read data in chunks */
rv = ec_flash_read(buf, offset, size);
if (rv < 0) {
free(buf);
return rv;
}
rv = write_file(argv[3], buf, size);
free(buf);
if (rv)
return rv;
printf("done.\n");
return 0;
}
int cmd_flash_write(int argc, char *argv[])
{
int offset, size;
int rv;
char *e;
char *buf;
if (argc < 3) {
fprintf(stderr, "Usage: %s <offset> <filename>\n", argv[0]);
return -1;
}
offset = strtol(argv[1], &e, 0);
if ((e && *e) || offset < 0 || offset > 0x100000) {
fprintf(stderr, "Bad offset.\n");
return -1;
}
/* Read the input file */
buf = read_file(argv[2], &size);
if (!buf)
return -1;
printf("Writing to offset %d...\n", offset);
/* Write data in chunks */
rv = ec_flash_write(buf, offset, size);
free(buf);
if (rv < 0)
return rv;
printf("done.\n");
return 0;
}
int cmd_flash_erase(int argc, char *argv[])
{
int offset, size;
char *e;
int rv;
if (argc < 3) {
fprintf(stderr, "Usage: %s <offset> <size>\n", argv[0]);
return -1;
}
offset = strtol(argv[1], &e, 0);
if ((e && *e) || offset < 0 || offset > 0x100000) {
fprintf(stderr, "Bad offset.\n");
return -1;
}
size = strtol(argv[2], &e, 0);
if ((e && *e) || size <= 0 || size > 0x100000) {
fprintf(stderr, "Bad size.\n");
return -1;
}
printf("Erasing %d bytes at offset %d...\n", size, offset);
rv = ec_flash_erase(offset, size);
if (rv < 0)
return rv;
printf("done.\n");
return 0;
}
static void print_flash_protect_flags(const char *desc, uint32_t flags)
{
printf("%s 0x%08x", desc, flags);
if (flags & EC_FLASH_PROTECT_GPIO_ASSERTED)
printf(" wp_gpio_asserted");
if (flags & EC_FLASH_PROTECT_RO_AT_BOOT)
printf(" ro_at_boot");
if (flags & EC_FLASH_PROTECT_ALL_AT_BOOT)
printf(" all_at_boot");
if (flags & EC_FLASH_PROTECT_RO_NOW)
printf(" ro_now");
if (flags & EC_FLASH_PROTECT_ALL_NOW)
printf(" all_now");
if (flags & EC_FLASH_PROTECT_ERROR_STUCK)
printf(" STUCK");
if (flags & EC_FLASH_PROTECT_ERROR_INCONSISTENT)
printf(" INCONSISTENT");
printf("\n");
}
int cmd_flash_protect(int argc, char *argv[])
{
struct ec_params_flash_protect p;
struct ec_response_flash_protect r;
int rv, i;
/*
* Set up requested flags. If no flags were specified, p.mask will
* be 0 and nothing will change.
*/
p.mask = p.flags = 0;
for (i = 1; i < argc; i++) {
if (!strcasecmp(argv[i], "now")) {
p.mask |= EC_FLASH_PROTECT_ALL_NOW;
p.flags |= EC_FLASH_PROTECT_ALL_NOW;
} else if (!strcasecmp(argv[i], "enable")) {
p.mask |= EC_FLASH_PROTECT_RO_AT_BOOT;
p.flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
} else if (!strcasecmp(argv[i], "disable"))
p.mask |= EC_FLASH_PROTECT_RO_AT_BOOT;
}
rv = ec_command(EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT,
&p, sizeof(p), &r, sizeof(r));
if (rv < 0)
return rv;
if (rv < sizeof(r)) {
fprintf(stderr, "Too little data returned.\n");
return -1;
}
/* Print returned flags */
print_flash_protect_flags("Flash protect flags:", r.flags);
print_flash_protect_flags("Valid flags: ", r.valid_flags);
print_flash_protect_flags("Writable flags: ", r.writable_flags);
/* Check if we got all the flags we asked for */
if ((r.flags & p.mask) != (p.flags & p.mask)) {
fprintf(stderr, "Unable to set requested flags "
"(wanted mask 0x%08x flags 0x%08x)\n",
p.mask, p.flags);
if (p.mask & ~r.writable_flags)
fprintf(stderr, "Which is expected, because writable "
"mask is 0x%08x.\n", r.writable_flags);
return -1;
}
return 0;
}
int cmd_serial_test(int argc, char *argv[])
{
const char *c = "COM2 sample serial output from host!\r\n";
printf("Writing sample serial output to COM2\n");
while (*c) {
/* Wait for space in transmit FIFO */
while (!(inb(0x2fd) & 0x20))
;
/* Put the next character */
outb(*c++, 0x2f8);
}
printf("done.\n");
return 0;
}
int read_mapped_temperature(int id)
{
int rv;
if (!read_mapped_mem8(EC_MEMMAP_THERMAL_VERSION)) {
/*
* The temp_sensor_init() is not called, which implies no
* temp sensor is defined.
*/
rv = EC_TEMP_SENSOR_NOT_PRESENT;
} else if (id < EC_TEMP_SENSOR_ENTRIES)
rv = read_mapped_mem8(EC_MEMMAP_TEMP_SENSOR + id);
else if (read_mapped_mem8(EC_MEMMAP_THERMAL_VERSION) >= 2)
rv = read_mapped_mem8(EC_MEMMAP_TEMP_SENSOR_B +
id - EC_TEMP_SENSOR_ENTRIES);
else {
/* Sensor in second bank, but second bank isn't supported */
rv = EC_TEMP_SENSOR_NOT_PRESENT;
}
return rv;
}
int cmd_temperature(int argc, char *argv[])
{
int rv;
int id;
char *e;
if (argc != 2) {
fprintf(stderr, "Usage: %s <sensorid> | all\n", argv[0]);
return -1;
}
if (strcmp(argv[1], "all") == 0) {
for (id = 0;
id < EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES;
id++) {
rv = read_mapped_temperature(id);
switch (rv) {
case EC_TEMP_SENSOR_NOT_PRESENT:
break;
case EC_TEMP_SENSOR_ERROR:
fprintf(stderr, "Sensor %d error\n", id);
break;
case EC_TEMP_SENSOR_NOT_POWERED:
fprintf(stderr, "Sensor %d disabled\n", id);
break;
case EC_TEMP_SENSOR_NOT_CALIBRATED:
fprintf(stderr, "Sensor %d not calibrated\n",
id);
break;
default:
printf("%d: %d\n", id,
rv + EC_TEMP_SENSOR_OFFSET);
}
}
return 0;
}
id = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad sensor ID.\n");
return -1;
}
if (id < 0 ||
id >= EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES) {
printf("Sensor ID invalid.\n");
return -1;
}
printf("Reading temperature...");
rv = read_mapped_temperature(id);
switch (rv) {
case EC_TEMP_SENSOR_NOT_PRESENT:
printf("Sensor not present\n");
return -1;
case EC_TEMP_SENSOR_ERROR:
printf("Error\n");
return -1;
case EC_TEMP_SENSOR_NOT_POWERED:
printf("Sensor disabled/unpowered\n");
return -1;
case EC_TEMP_SENSOR_NOT_CALIBRATED:
fprintf(stderr, "Sensor not calibrated\n");
return -1;
default:
printf("%d\n", rv + EC_TEMP_SENSOR_OFFSET);
return 0;
}
}
int cmd_temp_sensor_info(int argc, char *argv[])
{
struct ec_params_temp_sensor_get_info p;
struct ec_response_temp_sensor_get_info r;
int rv;
char *e;
if (argc != 2) {
fprintf(stderr, "Usage: %s <sensorid> | all\n", argv[0]);
return -1;
}
if (strcmp(argv[1], "all") == 0) {
for (p.id = 0;
p.id < EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES;
p.id++) {
rv = ec_command(EC_CMD_TEMP_SENSOR_GET_INFO, 0,
&p, sizeof(p), &r, sizeof(r));
if (rv < 0)
continue;
printf("%d: %d %s\n", p.id, r.sensor_type,
r.sensor_name);
}
return 0;
}
p.id = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad sensor ID.\n");
return -1;
}
rv = ec_command(EC_CMD_TEMP_SENSOR_GET_INFO, 0,
&p, sizeof(p), &r, sizeof(r));
if (rv < 0)
return rv;
printf("Sensor name: %s\n", r.sensor_name);
printf("Sensor type: %d\n", r.sensor_type);
return 0;
}
int cmd_thermal_get_threshold_v0(int argc, char *argv[])
{
struct ec_params_thermal_get_threshold p;
struct ec_response_thermal_get_threshold r;
char *e;
int rv;
if (argc != 3) {
fprintf(stderr,
"Usage: %s <sensortypeid> <thresholdid>\n", argv[0]);
return -1;
}
p.sensor_type = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad sensor type ID.\n");
return -1;
}
p.threshold_id = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad threshold ID.\n");
return -1;
}
rv = ec_command(EC_CMD_THERMAL_GET_THRESHOLD, 0,
&p, sizeof(p), &r, sizeof(r));
if (rv < 0)
return rv;
if (r.value < 0)
return -1;
printf("Threshold %d for sensor type %d is %d K.\n",
p.threshold_id, p.sensor_type, r.value);
return 0;
}
int cmd_thermal_set_threshold_v0(int argc, char *argv[])
{
struct ec_params_thermal_set_threshold p;
char *e;
int rv;
if (argc != 4) {
fprintf(stderr,
"Usage: %s <sensortypeid> <thresholdid> <value>\n",
argv[0]);
return -1;
}
p.sensor_type = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad sensor type ID.\n");
return -1;
}
p.threshold_id = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad threshold ID.\n");
return -1;
}
p.value = strtol(argv[3], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad threshold value.\n");
return -1;
}
rv = ec_command(EC_CMD_THERMAL_SET_THRESHOLD, 0,
&p, sizeof(p), NULL, 0);
if (rv < 0)
return rv;
printf("Threshold %d for sensor type %d set to %d.\n",
p.threshold_id, p.sensor_type, p.value);
return 0;
}
int cmd_thermal_get_threshold_v1(int argc, char *argv[])
{
struct ec_params_thermal_get_threshold_v1 p;
struct ec_thermal_config r;
struct ec_params_temp_sensor_get_info pi;
struct ec_response_temp_sensor_get_info ri;
int rv;
int i;
printf("sensor warn high halt fan_off fan_max name\n");
for (i = 0; i < 99; i++) { /* number of sensors is unknown */
/* ask for one */
p.sensor_num = i;
rv = ec_command(EC_CMD_THERMAL_GET_THRESHOLD, 1,
&p, sizeof(p), &r, sizeof(r));
if (rv <= 0) /* stop on first failure */
break;
/* ask for its name, too */
pi.id = i;
rv = ec_command(EC_CMD_TEMP_SENSOR_GET_INFO, 0,
&pi, sizeof(pi), &ri, sizeof(ri));
/* print what we know */
printf(" %2d %3d %3d %3d %3d %3d %s\n",
i,
r.temp_host[EC_TEMP_THRESH_WARN],
r.temp_host[EC_TEMP_THRESH_HIGH],
r.temp_host[EC_TEMP_THRESH_HALT],
r.temp_fan_off, r.temp_fan_max,
rv > 0 ? ri.sensor_name : "?");
}
if (i)
printf("(all temps in degrees Kelvin)\n");
return 0;
}
int cmd_thermal_set_threshold_v1(int argc, char *argv[])
{
struct ec_params_thermal_get_threshold_v1 p;
struct ec_thermal_config r;
struct ec_params_thermal_set_threshold_v1 s;
int i, n, val, rv;
char *e;
if (argc < 3 || argc > 7) {
printf("Usage: %s"
" sensor warn [high [shutdown [fan_off [fan_max]]]]\n",
argv[0]);
return 1;
}
n = strtod(argv[1], &e);
if (e && *e) {
printf("arg %d is invalid\n", 1);
return 1;
}
p.sensor_num = n;
rv = ec_command(EC_CMD_THERMAL_GET_THRESHOLD, 1,
&p, sizeof(p), &r, sizeof(r));
if (rv <= 0)
return rv;
s.sensor_num = n;
s.cfg = r;
for (i = 2; i < argc; i++) {
val = strtod(argv[i], &e);
if (e && *e) {
printf("arg %d is invalid\n", i);
return 1;
}
if (val < 0)
continue;
switch (i) {
case 2:
case 3:
case 4:
s.cfg.temp_host[i-2] = val;
break;
case 5:
s.cfg.temp_fan_off = val;
break;
case 6:
s.cfg.temp_fan_max = val;
break;
}
}
rv = ec_command(EC_CMD_THERMAL_SET_THRESHOLD, 1,
&s, sizeof(s), NULL, 0);
return rv;
}
/**
* Detect the version of EC_CMD_THERMAL_GET_THRESHOLD that the EC supports.
*
* @return The version, or -1 if error.
*/
static int thermal_threshold_version(void)
{
struct ec_params_thermal_get_threshold v0_p;
struct ec_response_thermal_get_threshold v0_r;
struct ec_params_thermal_get_threshold_v1 v1_p;
struct ec_thermal_config v1_r;
int rv;
v1_p.sensor_num = 0;
rv = ec_command(EC_CMD_THERMAL_GET_THRESHOLD, 1,
&v1_p, sizeof(v1_p), &v1_r, sizeof(v1_r));
/*
* TODO(crosbug.com/p/23828): Version 1 of the threshold command will
* only return EC_RES_SUCCESS or EC_RES_INVALID_PARAM?
*/
if (rv > 0)
return 1;
v0_p.sensor_type = 0;
v0_p.threshold_id = 0;
rv = ec_command(EC_CMD_THERMAL_GET_THRESHOLD, 0,
&v0_p, sizeof(v0_p), &v0_r, sizeof(v0_r));
/*
* TODO(crosbug.com/p/23828): Version 0 of the threshold command will
* only return EC_RES_SUCCESS or EC_RES_ERROR?
*/
if (rv > 0)
return 0;
/*
* Anything else is most likely EC_RES_INVALID_COMMAND, but we don't
* care because it's nothing we can use.
*/
return -1;
}
int cmd_thermal_get_threshold(int argc, char *argv[])
{
switch (thermal_threshold_version()) {
case 0:
return cmd_thermal_get_threshold_v0(argc, argv);
case 1:
return cmd_thermal_get_threshold_v1(argc, argv);
default:
printf("I got nuthin.\n");
return -1;
}
}
int cmd_thermal_set_threshold(int argc, char *argv[])
{
switch (thermal_threshold_version()) {
case 0:
return cmd_thermal_set_threshold_v0(argc, argv);
case 1:
return cmd_thermal_set_threshold_v1(argc, argv);
default:
printf("I got nuthin.\n");
return -1;
}
}
int cmd_thermal_auto_fan_ctrl(int argc, char *argv[])
{
int rv;
rv = ec_command(EC_CMD_THERMAL_AUTO_FAN_CTRL, 0, NULL, 0, NULL, 0);
if (rv < 0)
return rv;
printf("Automatic fan control is now on.\n");
return 0;
}
static int print_fan(int idx)
{
int rv = read_mapped_mem16(EC_MEMMAP_FAN + 2 * idx);
switch (rv) {
case EC_FAN_SPEED_NOT_PRESENT:
return -1;
case EC_FAN_SPEED_STALLED:
printf("Fan %d stalled!\n", idx);
break;
default:
printf("Fan %d RPM: %d\n", idx, rv);
break;
}
return 0;
}
int cmd_pwm_get_fan_rpm(int argc, char *argv[])
{
int i;
if (argc < 2 || !strcasecmp(argv[1], "all")) {
/* Print all the fan speeds */
for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
if (print_fan(i))
break; /* Stop at first not-present fan */
}
} else {
char *e;
int idx;
idx = strtol(argv[1], &e, 0);
if ((e && *e) || idx < 0 || idx >= EC_FAN_SPEED_ENTRIES) {
fprintf(stderr, "Bad index.\n");
return -1;
}
return print_fan(idx);
}
return 0;
}
int cmd_pwm_set_fan_rpm(int argc, char *argv[])
{
struct ec_params_pwm_set_fan_target_rpm p;
char *e;
int rv;
if (argc != 2) {
fprintf(stderr,
"Usage: %s <targetrpm>\n", argv[0]);
return -1;
}
p.rpm = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad RPM.\n");
return -1;
}
rv = ec_command(EC_CMD_PWM_SET_FAN_TARGET_RPM, 0,
&p, sizeof(p), NULL, 0);
if (rv < 0)
return rv;
printf("Fan target RPM set.\n");
return 0;
}
int cmd_pwm_get_keyboard_backlight(int argc, char *argv[])
{
struct ec_response_pwm_get_keyboard_backlight r;
int rv;
rv = ec_command(EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT, 0,
NULL, 0, &r, sizeof(r));
if (rv < 0)
return rv;
if (r.enabled == 1)
printf("Current keyboard backlight percent: %d\n", r.percent);
else
printf("Keyboard backlight disabled.\n");
return 0;
}
int cmd_pwm_set_keyboard_backlight(int argc, char *argv[])
{
struct ec_params_pwm_set_keyboard_backlight p;
char *e;
int rv;
if (argc != 2) {
fprintf(stderr, "Usage: %s <percent>\n", argv[0]);
return -1;
}
p.percent = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad percent.\n");
return -1;
}
rv = ec_command(EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT, 0,
&p, sizeof(p), NULL, 0);
if (rv < 0)
return rv;
printf("Keyboard backlight set.\n");
return 0;
}
int cmd_fanduty(int argc, char *argv[])
{
struct ec_params_pwm_set_fan_duty p;
char *e;
int rv;
if (argc != 2) {
fprintf(stderr,
"Usage: %s <targetrpm>\n", argv[0]);
return -1;
}
p.percent = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad percent arg.\n");
return -1;
}
rv = ec_command(EC_CMD_PWM_SET_FAN_DUTY, 0, &p, sizeof(p), NULL, 0);
if (rv < 0)
return rv;
printf("Fan duty cycle set.\n");
return 0;
}
#define LBMSG(state) #state
#include "lightbar_msg_list.h"
static const char * const lightbar_cmds[] = {
LIGHTBAR_MSG_LIST
};
#undef LBMSG
/* This needs to match the values defined in lightbar.h. I'd like to
* define this in one and only one place, but I can't think of a good way to do
* that without adding bunch of complexity. This will do for now.
*/
#define LB_SIZES(SUBCMD) { \
sizeof(((struct ec_params_lightbar *)0)->SUBCMD) \
+ sizeof(((struct ec_params_lightbar *)0)->cmd), \
sizeof(((struct ec_response_lightbar *)0)->SUBCMD) }
static const struct {
uint8_t insize;
uint8_t outsize;
} lb_command_paramcount[] = {
LB_SIZES(dump),
LB_SIZES(off),
LB_SIZES(on),
LB_SIZES(init),
LB_SIZES(set_brightness),
LB_SIZES(seq),
LB_SIZES(reg),
LB_SIZES(set_rgb),
LB_SIZES(get_seq),
LB_SIZES(demo),
LB_SIZES(get_params_v0),
LB_SIZES(set_params_v0),
LB_SIZES(version),
LB_SIZES(get_brightness),
LB_SIZES(get_rgb),
LB_SIZES(get_demo),
LB_SIZES(get_params_v1),
LB_SIZES(set_params_v1),
};
#undef LB_SIZES
static int lb_help(const char *cmd)
{
printf("Usage:\n");
printf(" %s - dump all regs\n", cmd);
printf(" %s off - enter standby\n", cmd);
printf(" %s on - leave standby\n", cmd);
printf(" %s init - load default vals\n", cmd);
printf(" %s brightness [NUM] - get/set intensity (0-ff)\n", cmd);
printf(" %s seq [NUM|SEQUENCE] - run given pattern"
" (no arg for list)\n", cmd);
printf(" %s CTRL REG VAL - set LED controller regs\n", cmd);
printf(" %s LED RED GREEN BLUE - set color manually"
" (LED=4 for all)\n", cmd);
printf(" %s LED - get current LED color\n", cmd);
printf(" %s demo [0|1] - turn demo mode on & off\n", cmd);
printf(" %s params [setfile] - get params"
" (or set from file)\n", cmd);
return 0;
}
static uint8_t lb_find_msg_by_name(const char *str)
{
uint8_t i;
for (i = 0; i < LIGHTBAR_NUM_SEQUENCES; i++)
if (!strcasecmp(str, lightbar_cmds[i]))
return i;
return LIGHTBAR_NUM_SEQUENCES;
}
static int lb_do_cmd(enum lightbar_command cmd,
struct ec_params_lightbar *in,
struct ec_response_lightbar *out)
{
int rv;
in->cmd = cmd;
rv = ec_command(EC_CMD_LIGHTBAR_CMD, 0,
in, lb_command_paramcount[cmd].insize,
out, lb_command_paramcount[cmd].outsize);
return (rv < 0 ? rv : 0);
}
static int lb_show_msg_names(void)
{
int i, current_state;
struct ec_params_lightbar param;
struct ec_response_lightbar resp;
i = lb_do_cmd(LIGHTBAR_CMD_GET_SEQ, &param, &resp);
if (i < 0)
return i;
current_state = resp.get_seq.num;
printf("sequence names:");
for (i = 0; i < LIGHTBAR_NUM_SEQUENCES; i++)
printf(" %s", lightbar_cmds[i]);
printf("\nCurrent = 0x%x %s\n", current_state,
lightbar_cmds[current_state]);
return 0;
}
static int lb_read_params_v0_from_file(const char *filename,
struct lightbar_params_v0 *p)
{
FILE *fp;
char buf[80];
int val[4];
int r = 1;
int line = 0;
int want, got;
int i;
fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Can't open %s: %s\n",
filename, strerror(errno));
return 1;
}
/* We must read the correct number of params from each line */
#define READ(N) do { \
line++; \
want = (N); \
got = -1; \
if (!fgets(buf, sizeof(buf), fp)) \
goto done; \
got = sscanf(buf, "%i %i %i %i", \
&val[0], &val[1], &val[2], &val[3]); \
if (want != got) \
goto done; \
} while (0)
/* Do it */
READ(1); p->google_ramp_up = val[0];
READ(1); p->google_ramp_down = val[0];
READ(1); p->s3s0_ramp_up = val[0];
READ(1); p->s0_tick_delay[0] = val[0];
READ(1); p->s0_tick_delay[1] = val[0];
READ(1); p->s0a_tick_delay[0] = val[0];
READ(1); p->s0a_tick_delay[1] = val[0];
READ(1); p->s0s3_ramp_down = val[0];
READ(1); p->s3_sleep_for = val[0];
READ(1); p->s3_ramp_up = val[0];
READ(1); p->s3_ramp_down = val[0];
READ(1); p->new_s0 = val[0];
READ(2);
p->osc_min[0] = val[0];
p->osc_min[1] = val[1];
READ(2);
p->osc_max[0] = val[0];
p->osc_max[1] = val[1];
READ(2);
p->w_ofs[0] = val[0];
p->w_ofs[1] = val[1];
READ(2);
p->bright_bl_off_fixed[0] = val[0];
p->bright_bl_off_fixed[1] = val[1];
READ(2);
p->bright_bl_on_min[0] = val[0];
p->bright_bl_on_min[1] = val[1];
READ(2);
p->bright_bl_on_max[0] = val[0];
p->bright_bl_on_max[1] = val[1];
READ(3);
p->battery_threshold[0] = val[0];
p->battery_threshold[1] = val[1];
p->battery_threshold[2] = val[2];
READ(4);
p->s0_idx[0][0] = val[0];
p->s0_idx[0][1] = val[1];
p->s0_idx[0][2] = val[2];
p->s0_idx[0][3] = val[3];
READ(4);
p->s0_idx[1][0] = val[0];
p->s0_idx[1][1] = val[1];
p->s0_idx[1][2] = val[2];
p->s0_idx[1][3] = val[3];
READ(4);
p->s3_idx[0][0] = val[0];
p->s3_idx[0][1] = val[1];
p->s3_idx[0][2] = val[2];
p->s3_idx[0][3] = val[3];
READ(4);
p->s3_idx[1][0] = val[0];
p->s3_idx[1][1] = val[1];
p->s3_idx[1][2] = val[2];
p->s3_idx[1][3] = val[3];
for (i = 0; i < ARRAY_SIZE(p->color); i++) {
READ(3);
p->color[i].r = val[0];
p->color[i].g = val[1];
p->color[i].b = val[2];
}
#undef READ
/* Yay */
r = 0;
done:
if (r)
fprintf(stderr, "problem with line %d: wanted %d, got %d\n",
line, want, got);
fclose(fp);
return r;
}
static void lb_show_params_v0(const struct lightbar_params_v0 *p)
{
int i;
printf("%d\t\t# .google_ramp_up\n", p->google_ramp_up);
printf("%d\t\t# .google_ramp_down\n", p->google_ramp_down);
printf("%d\t\t# .s3s0_ramp_up\n", p->s3s0_ramp_up);
printf("%d\t\t# .s0_tick_delay (battery)\n", p->s0_tick_delay[0]);
printf("%d\t\t# .s0_tick_delay (AC)\n", p->s0_tick_delay[1]);
printf("%d\t\t# .s0a_tick_delay (battery)\n", p->s0a_tick_delay[0]);
printf("%d\t\t# .s0a_tick_delay (AC)\n", p->s0a_tick_delay[1]);
printf("%d\t\t# .s0s3_ramp_down\n", p->s0s3_ramp_down);
printf("%d\t# .s3_sleep_for\n", p->s3_sleep_for);
printf("%d\t\t# .s3_ramp_up\n", p->s3_ramp_up);
printf("%d\t\t# .s3_ramp_down\n", p->s3_ramp_down);
printf("%d\t\t# .new_s0\n", p->new_s0);
printf("0x%02x 0x%02x\t# .osc_min (battery, AC)\n",
p->osc_min[0], p->osc_min[1]);
printf("0x%02x 0x%02x\t# .osc_max (battery, AC)\n",
p->osc_max[0], p->osc_max[1]);
printf("%d %d\t\t# .w_ofs (battery, AC)\n",
p->w_ofs[0], p->w_ofs[1]);
printf("0x%02x 0x%02x\t# .bright_bl_off_fixed (battery, AC)\n",
p->bright_bl_off_fixed[0], p->bright_bl_off_fixed[1]);
printf("0x%02x 0x%02x\t# .bright_bl_on_min (battery, AC)\n",
p->bright_bl_on_min[0], p->bright_bl_on_min[1]);
printf("0x%02x 0x%02x\t# .bright_bl_on_max (battery, AC)\n",
p->bright_bl_on_max[0], p->bright_bl_on_max[1]);
printf("%d %d %d\t\t# .battery_threshold\n",
p->battery_threshold[0],
p->battery_threshold[1],
p->battery_threshold[2]);
printf("%d %d %d %d\t\t# .s0_idx[] (battery)\n",
p->s0_idx[0][0], p->s0_idx[0][1],
p->s0_idx[0][2], p->s0_idx[0][3]);
printf("%d %d %d %d\t\t# .s0_idx[] (AC)\n",
p->s0_idx[1][0], p->s0_idx[1][1],
p->s0_idx[1][2], p->s0_idx[1][3]);
printf("%d %d %d %d\t# .s3_idx[] (battery)\n",
p->s3_idx[0][0], p->s3_idx[0][1],
p->s3_idx[0][2], p->s3_idx[0][3]);
printf("%d %d %d %d\t# .s3_idx[] (AC)\n",
p->s3_idx[1][0], p->s3_idx[1][1],
p->s3_idx[1][2], p->s3_idx[1][3]);
for (i = 0; i < ARRAY_SIZE(p->color); i++)
printf("0x%02x 0x%02x 0x%02x\t# color[%d]\n",
p->color[i].r,
p->color[i].g,
p->color[i].b, i);
}
static int lb_read_params_v1_from_file(const char *filename,
struct lightbar_params_v1 *p)
{
FILE *fp;
char buf[80];
int val[4];
int r = 1;
int line = 0;
int want, got;
int i;
fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Can't open %s: %s\n",
filename, strerror(errno));
return 1;
}
/* We must read the correct number of params from each line */
#define READ(N) do { \
line++; \
want = (N); \
got = -1; \
if (!fgets(buf, sizeof(buf), fp)) \
goto done; \
got = sscanf(buf, "%i %i %i %i", \
&val[0], &val[1], &val[2], &val[3]); \
if (want != got) \
goto done; \
} while (0)
/* Do it */
READ(1); p->google_ramp_up = val[0];
READ(1); p->google_ramp_down = val[0];
READ(1); p->s3s0_ramp_up = val[0];
READ(1); p->s0_tick_delay[0] = val[0];
READ(1); p->s0_tick_delay[1] = val[0];
READ(1); p->s0a_tick_delay[0] = val[0];
READ(1); p->s0a_tick_delay[1] = val[0];
READ(1); p->s0s3_ramp_down = val[0];
READ(1); p->s3_sleep_for = val[0];
READ(1); p->s3_ramp_up = val[0];
READ(1); p->s3_ramp_down = val[0];
READ(1); p->tap_tick_delay = val[0];
READ(1); p->tap_display_time = val[0];
READ(1); p->tap_pct_red = val[0];
READ(1); p->tap_pct_green = val[0];
READ(1); p->tap_seg_min_on = val[0];
READ(1); p->tap_seg_max_on = val[0];
READ(1); p->tap_seg_osc = val[0];
READ(3);
p->tap_idx[0] = val[0];
p->tap_idx[1] = val[1];
p->tap_idx[2] = val[2];
READ(2);
p->osc_min[0] = val[0];
p->osc_min[1] = val[1];
READ(2);
p->osc_max[0] = val[0];
p->osc_max[1] = val[1];
READ(2);
p->w_ofs[0] = val[0];
p->w_ofs[1] = val[1];
READ(2);
p->bright_bl_off_fixed[0] = val[0];
p->bright_bl_off_fixed[1] = val[1];
READ(2);
p->bright_bl_on_min[0] = val[0];
p->bright_bl_on_min[1] = val[1];
READ(2);
p->bright_bl_on_max[0] = val[0];
p->bright_bl_on_max[1] = val[1];
READ(3);
p->battery_threshold[0] = val[0];
p->battery_threshold[1] = val[1];
p->battery_threshold[2] = val[2];
READ(4);
p->s0_idx[0][0] = val[0];
p->s0_idx[0][1] = val[1];
p->s0_idx[0][2] = val[2];
p->s0_idx[0][3] = val[3];
READ(4);
p->s0_idx[1][0] = val[0];
p->s0_idx[1][1] = val[1];
p->s0_idx[1][2] = val[2];
p->s0_idx[1][3] = val[3];
READ(4);
p->s3_idx[0][0] = val[0];
p->s3_idx[0][1] = val[1];
p->s3_idx[0][2] = val[2];
p->s3_idx[0][3] = val[3];
READ(4);
p->s3_idx[1][0] = val[0];
p->s3_idx[1][1] = val[1];
p->s3_idx[1][2] = val[2];
p->s3_idx[1][3] = val[3];
for (i = 0; i < ARRAY_SIZE(p->color); i++) {
READ(3);
p->color[i].r = val[0];
p->color[i].g = val[1];
p->color[i].b = val[2];
}
#undef READ
/* Yay */
r = 0;
done:
if (r)
fprintf(stderr, "problem with line %d: wanted %d, got %d\n",
line, want, got);
fclose(fp);
return r;
}
static void lb_show_params_v1(const struct lightbar_params_v1 *p)
{
int i;
printf("%d\t\t# .google_ramp_up\n", p->google_ramp_up);
printf("%d\t\t# .google_ramp_down\n", p->google_ramp_down);
printf("%d\t\t# .s3s0_ramp_up\n", p->s3s0_ramp_up);
printf("%d\t\t# .s0_tick_delay (battery)\n", p->s0_tick_delay[0]);
printf("%d\t\t# .s0_tick_delay (AC)\n", p->s0_tick_delay[1]);
printf("%d\t\t# .s0a_tick_delay (battery)\n", p->s0a_tick_delay[0]);
printf("%d\t\t# .s0a_tick_delay (AC)\n", p->s0a_tick_delay[1]);
printf("%d\t\t# .s0s3_ramp_down\n", p->s0s3_ramp_down);
printf("%d\t\t# .s3_sleep_for\n", p->s3_sleep_for);
printf("%d\t\t# .s3_ramp_up\n", p->s3_ramp_up);
printf("%d\t\t# .s3_ramp_down\n", p->s3_ramp_down);
printf("%d\t\t# .tap_tick_delay\n", p->tap_tick_delay);
printf("%d\t\t# .tap_display_time\n", p->tap_display_time);
printf("%d\t\t# .tap_pct_red\n", p->tap_pct_red);
printf("%d\t\t# .tap_pct_green\n", p->tap_pct_green);
printf("%d\t\t# .tap_seg_min_on\n", p->tap_seg_min_on);
printf("%d\t\t# .tap_seg_max_on\n", p->tap_seg_max_on);
printf("%d\t\t# .tap_seg_osc\n", p->tap_seg_osc);
printf("%d %d %d\t\t# .tap_idx\n",
p->tap_idx[0], p->tap_idx[1], p->tap_idx[2]);
printf("0x%02x 0x%02x\t# .osc_min (battery, AC)\n",
p->osc_min[0], p->osc_min[1]);
printf("0x%02x 0x%02x\t# .osc_max (battery, AC)\n",
p->osc_max[0], p->osc_max[1]);
printf("%d %d\t\t# .w_ofs (battery, AC)\n",
p->w_ofs[0], p->w_ofs[1]);
printf("0x%02x 0x%02x\t# .bright_bl_off_fixed (battery, AC)\n",
p->bright_bl_off_fixed[0], p->bright_bl_off_fixed[1]);
printf("0x%02x 0x%02x\t# .bright_bl_on_min (battery, AC)\n",
p->bright_bl_on_min[0], p->bright_bl_on_min[1]);
printf("0x%02x 0x%02x\t# .bright_bl_on_max (battery, AC)\n",
p->bright_bl_on_max[0], p->bright_bl_on_max[1]);
printf("%d %d %d\t# .battery_threshold\n",
p->battery_threshold[0],
p->battery_threshold[1],
p->battery_threshold[2]);
printf("%d %d %d %d\t\t# .s0_idx[] (battery)\n",
p->s0_idx[0][0], p->s0_idx[0][1],
p->s0_idx[0][2], p->s0_idx[0][3]);
printf("%d %d %d %d\t\t# .s0_idx[] (AC)\n",
p->s0_idx[1][0], p->s0_idx[1][1],
p->s0_idx[1][2], p->s0_idx[1][3]);
printf("%d %d %d %d\t# .s3_idx[] (battery)\n",
p->s3_idx[0][0], p->s3_idx[0][1],
p->s3_idx[0][2], p->s3_idx[0][3]);
printf("%d %d %d %d\t# .s3_idx[] (AC)\n",
p->s3_idx[1][0], p->s3_idx[1][1],
p->s3_idx[1][2], p->s3_idx[1][3]);
for (i = 0; i < ARRAY_SIZE(p->color); i++)
printf("0x%02x 0x%02x 0x%02x\t# color[%d]\n",
p->color[i].r,
p->color[i].g,
p->color[i].b, i);
}
static int cmd_lightbar_params_v0(int argc, char **argv)
{
struct ec_params_lightbar param;
struct ec_response_lightbar resp;
int r;
if (argc > 2) {
r = lb_read_params_v0_from_file(argv[2],
&param.set_params_v0);
if (r)
return r;
return lb_do_cmd(LIGHTBAR_CMD_SET_PARAMS_V0,
&param, &resp);
}
r = lb_do_cmd(LIGHTBAR_CMD_GET_PARAMS_V0, &param, &resp);
if (!r)
lb_show_params_v0(&resp.get_params_v0);
return r;
}
static int cmd_lightbar_params_v1(int argc, char **argv)
{
struct ec_params_lightbar param;
struct ec_response_lightbar resp;
int r;
if (argc > 2) {
r = lb_read_params_v1_from_file(argv[2],
&param.set_params_v1);
if (r)
return r;
return lb_do_cmd(LIGHTBAR_CMD_SET_PARAMS_V1,
&param, &resp);
}
r = lb_do_cmd(LIGHTBAR_CMD_GET_PARAMS_V1, &param, &resp);
if (!r)
lb_show_params_v1(&resp.get_params_v1);
return r;
}
static int cmd_lightbar(int argc, char **argv)
{
int i, r;
struct ec_params_lightbar param;
struct ec_response_lightbar resp;
if (1 == argc) { /* no args = dump 'em all */
r = lb_do_cmd(LIGHTBAR_CMD_DUMP, &param, &resp);
if (r)
return r;
for (i = 0; i < ARRAY_SIZE(resp.dump.vals); i++) {
printf(" %02x %02x %02x\n",
resp.dump.vals[i].reg,
resp.dump.vals[i].ic0,
resp.dump.vals[i].ic1);
}
return 0;
}
if (argc == 2 && !strcasecmp(argv[1], "init"))
return lb_do_cmd(LIGHTBAR_CMD_INIT, &param, &resp);
if (argc == 2 && !strcasecmp(argv[1], "off"))
return lb_do_cmd(LIGHTBAR_CMD_OFF, &param, &resp);
if (argc == 2 && !strcasecmp(argv[1], "on"))
return lb_do_cmd(LIGHTBAR_CMD_ON, &param, &resp);
if (!strcasecmp(argv[1], "params0"))
return cmd_lightbar_params_v0(argc, argv);
if (!strcasecmp(argv[1], "params1"))
return cmd_lightbar_params_v1(argc, argv);
if (!strcasecmp(argv[1], "params")) {
/* Just try them both */
fprintf(stderr, "trying params1 ...\n");
if (0 == cmd_lightbar_params_v1(argc, argv))
return 0;
fprintf(stderr, "trying params0 ...\n");
return cmd_lightbar_params_v0(argc, argv);
}
if (!strcasecmp(argv[1], "version")) {
r = lb_do_cmd(LIGHTBAR_CMD_VERSION, &param, &resp);
if (!r)
printf("version %d flags 0x%x\n",
resp.version.num, resp.version.flags);
return r;
}
if (argc > 1 && !strcasecmp(argv[1], "brightness")) {
char *e;
int rv;
if (argc > 2) {
param.set_brightness.num = 0xff &
strtoul(argv[2], &e, 16);
return lb_do_cmd(LIGHTBAR_CMD_SET_BRIGHTNESS,
&param, &resp);
}
rv = lb_do_cmd(LIGHTBAR_CMD_GET_BRIGHTNESS,
&param, &resp);
if (rv)
return rv;
printf("%02x\n", resp.get_brightness.num);
return 0;
}
if (argc > 1 && !strcasecmp(argv[1], "demo")) {
int rv;
if (argc > 2) {
if (!strcasecmp(argv[2], "on") || argv[2][0] == '1')
param.demo.num = 1;
else if (!strcasecmp(argv[2], "off") ||
argv[2][0] == '0')
param.demo.num = 0;
else {
fprintf(stderr, "Invalid arg\n");
return -1;
}
return lb_do_cmd(LIGHTBAR_CMD_DEMO, &param, &resp);
}
rv = lb_do_cmd(LIGHTBAR_CMD_GET_DEMO, &param, &resp);
if (rv)
return rv;
printf("%s\n", resp.get_demo.num ? "on" : "off");
return 0;
}
if (argc >= 2 && !strcasecmp(argv[1], "seq")) {
char *e;
uint8_t num;
if (argc == 2)
return lb_show_msg_names();
num = 0xff & strtoul(argv[2], &e, 16);
if (e && *e)
num = lb_find_msg_by_name(argv[2]);
if (num >= LIGHTBAR_NUM_SEQUENCES) {
fprintf(stderr, "Invalid arg\n");
return -1;
}
param.seq.num = num;
return lb_do_cmd(LIGHTBAR_CMD_SEQ, &param, &resp);
}
if (argc == 4) {
char *e;
param.reg.ctrl = 0xff & strtoul(argv[1], &e, 16);
param.reg.reg = 0xff & strtoul(argv[2], &e, 16);
param.reg.value = 0xff & strtoul(argv[3], &e, 16);
return lb_do_cmd(LIGHTBAR_CMD_REG, &param, &resp);
}
if (argc == 5) {
char *e;
param.set_rgb.led = strtoul(argv[1], &e, 16);
param.set_rgb.red = strtoul(argv[2], &e, 16);
param.set_rgb.green = strtoul(argv[3], &e, 16);
param.set_rgb.blue = strtoul(argv[4], &e, 16);
return lb_do_cmd(LIGHTBAR_CMD_SET_RGB, &param, &resp);
}
/* Only thing left is to try to read an LED value */
if (argc == 2) {
char *e;
param.get_rgb.led = strtoul(argv[1], &e, 0);
if (!(e && *e)) {
r = lb_do_cmd(LIGHTBAR_CMD_GET_RGB, &param, &resp);
if (r)
return r;
printf("%02x %02x %02x\n",
resp.get_rgb.red,
resp.get_rgb.green,
resp.get_rgb.blue);
return 0;
}
}
return lb_help(argv[0]);
}
/* Create an array to store sizes of motion sense param and response structs. */
#define MS_SIZES(SUBCMD) { \
sizeof(((struct ec_params_motion_sense *)0)->SUBCMD) \
+ sizeof(((struct ec_params_motion_sense *)0)->cmd), \
sizeof(((struct ec_response_motion_sense *)0)->SUBCMD) }
static const struct {
uint8_t insize;
uint8_t outsize;
} ms_command_sizes[] = {
MS_SIZES(dump),
MS_SIZES(info),
MS_SIZES(ec_rate),
MS_SIZES(sensor_odr),
MS_SIZES(sensor_range),
MS_SIZES(kb_wake_angle),
};
BUILD_ASSERT(ARRAY_SIZE(ms_command_sizes) == MOTIONSENSE_NUM_CMDS);
#undef MS_SIZES
static int ms_help(const char *cmd)
{
printf("Usage:\n");
printf(" %s - dump all motion data\n", cmd);
printf(" %s active - print active flag\n", cmd);
printf(" %s info NUM - print sensor info\n", cmd);
printf(" %s ec_rate [RATE_MS] - set/get sample rate\n", cmd);
printf(" %s odr NUM [ODR [ROUNDUP]] - set/get sensor ODR\n", cmd);
printf(" %s range NUM [RANGE [ROUNDUP]]- set/get sensor range\n", cmd);
printf(" %s kb_wake NUM - set/get KB wake ang\n", cmd);
return 0;
}
static int cmd_motionsense(int argc, char **argv)
{
int i, rv;
struct ec_params_motion_sense param;
struct ec_response_motion_sense resp;
char *e;
/* No motionsense command has more than 5 args. */
if (argc > 5)
return ms_help(argv[0]);
if (argc == 1) {
/* No args, dump motion data. */
param.cmd = MOTIONSENSE_CMD_DUMP;
rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
&param, ms_command_sizes[param.cmd].insize,
&resp, ms_command_sizes[param.cmd].outsize);
if (rv < 0)
return rv;
if (resp.dump.module_flags & MOTIONSENSE_MODULE_FLAG_ACTIVE)
printf("Motion sensing active\n");
else
printf("Motion sensing inactive\n");
for (i = 0; i < EC_MOTION_SENSOR_COUNT; i++) {
printf("Sensor %d: ", i);
if (resp.dump.sensor_flags[i] &
MOTIONSENSE_SENSOR_FLAG_PRESENT)
printf("%d\t%d\t%d\n", resp.dump.data[3*i],
resp.dump.data[3*i+1],
resp.dump.data[3*i+2]);
else
/*
* Warning: the following string printed out
* is read by an autotest. Do not change string
* without consulting autotest for
* kernel_CrosECSysfsAccel.
*/
printf("None\n");
}
return 0;
}
if (argc == 2 && !strcasecmp(argv[1], "active")) {
param.cmd = MOTIONSENSE_CMD_DUMP;
rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
&param, ms_command_sizes[param.cmd].insize,
&resp, ms_command_sizes[param.cmd].outsize);
/*
* Warning: the following strings printed out are read in an
* autotest. Do not change string without consulting autotest
* for kernel_CrosECSysfsAccel.
*/
if (resp.dump.module_flags & MOTIONSENSE_MODULE_FLAG_ACTIVE)
printf("1\n");
else
printf("0\n");
return 0;
}
if (argc == 3 && !strcasecmp(argv[1], "info")) {
param.cmd = MOTIONSENSE_CMD_INFO;
param.sensor_odr.sensor_num = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
&param, ms_command_sizes[param.cmd].insize,
&resp, ms_command_sizes[param.cmd].outsize);
if (rv < 0)
return rv;
printf("Type: ");
switch (resp.info.type) {
case MOTIONSENSE_TYPE_ACCEL:
printf("accel\n");
break;
case MOTIONSENSE_TYPE_GYRO:
printf("gyro\n");
break;
default:
printf("unknown\n");
}
printf("Location: ");
switch (resp.info.location) {
case MOTIONSENSE_LOC_BASE:
printf("base\n");
break;
case MOTIONSENSE_LOC_LID:
printf("lid\n");
break;
default:
printf("unknown\n");
}
printf("Chip: ");
switch (resp.info.chip) {
case MOTIONSENSE_CHIP_KXCJ9:
printf("kxcj9\n");
break;
default:
printf("unknown\n");
}
return 0;
}
if (argc < 4 && !strcasecmp(argv[1], "ec_rate")) {
param.cmd = MOTIONSENSE_CMD_EC_RATE;
param.ec_rate.data = EC_MOTION_SENSE_NO_VALUE;
if (argc == 3) {
param.ec_rate.data = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
}
rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
&param, ms_command_sizes[param.cmd].insize,
&resp, ms_command_sizes[param.cmd].outsize);
if (rv < 0)
return rv;
printf("%d\n", resp.ec_rate.ret);
return 0;
}
if (argc > 2 && !strcasecmp(argv[1], "odr")) {
param.cmd = MOTIONSENSE_CMD_SENSOR_ODR;
param.sensor_odr.data = EC_MOTION_SENSE_NO_VALUE;
param.sensor_odr.roundup = 1;
param.sensor_odr.sensor_num = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
if (argc >= 4) {
param.sensor_odr.data = strtol(argv[3], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
}
if (argc == 5) {
param.sensor_odr.roundup = strtol(argv[4], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
}
rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
&param, ms_command_sizes[param.cmd].insize,
&resp, ms_command_sizes[param.cmd].outsize);
if (rv < 0)
return rv;
printf("%d\n", resp.sensor_odr.ret);
return 0;
}
if (argc > 2 && !strcasecmp(argv[1], "range")) {
param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
param.sensor_odr.roundup = 1;
param.sensor_range.sensor_num = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
if (argc >= 4) {
param.sensor_range.data = strtol(argv[3], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
}
if (argc == 5) {
param.sensor_odr.roundup = strtol(argv[4], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
}
rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
&param, ms_command_sizes[param.cmd].insize,
&resp, ms_command_sizes[param.cmd].outsize);
if (rv < 0)
return rv;
printf("%d\n", resp.sensor_range.ret);
return 0;
}
if (argc < 4 && !strcasecmp(argv[1], "kb_wake")) {
param.cmd = MOTIONSENSE_CMD_KB_WAKE_ANGLE;
param.kb_wake_angle.data = EC_MOTION_SENSE_NO_VALUE;
if (argc == 3) {
param.kb_wake_angle.data = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad %s arg.\n", argv[1]);
return -1;
}
}
rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
&param, ms_command_sizes[param.cmd].insize,
&resp, ms_command_sizes[param.cmd].outsize);
if (rv < 0)
return rv;
printf("%d\n", resp.kb_wake_angle.ret);
return 0;
}
return ms_help(argv[0]);
}
static int find_led_color_by_name(const char *color)
{
int i;
for (i = 0; i < EC_LED_COLOR_COUNT; ++i)
if (!strcasecmp(color, led_color_names[i]))
return i;
return -1;
}
static int find_led_id_by_name(const char *led)
{
int i;
for (i = 0; i < EC_LED_ID_COUNT; ++i)
if (!strcasecmp(led, led_names[i]))
return i;
return -1;
}
int cmd_led(int argc, char *argv[])
{
struct ec_params_led_control p;
struct ec_response_led_control r;
char *e, *ptr;
int rv, i, j;
memset(p.brightness, 0, sizeof(p.brightness));
p.flags = 0;
if (argc < 3) {
fprintf(stderr,
"Usage: %s <name> <query | auto | "
"off | <color> | <color>=<value>...>\n", argv[0]);
return -1;
}
p.led_id = find_led_id_by_name(argv[1]);
if (p.led_id == (uint8_t)-1) {
fprintf(stderr, "Bad LED name: %s\n", argv[1]);
fprintf(stderr, "Valid LED names: ");
for (i = 0; i < EC_LED_ID_COUNT; i++)
fprintf(stderr, "%s ", led_names[i]);
fprintf(stderr, "\n");
return -1;
}
if (!strcasecmp(argv[2], "query")) {
p.flags = EC_LED_FLAGS_QUERY;
rv = ec_command(EC_CMD_LED_CONTROL, 1, &p, sizeof(p),
&r, sizeof(r));
printf("Brightness range for LED %d:\n", p.led_id);
if (rv < 0) {
fprintf(stderr, "Error: Unsupported LED.\n");
return rv;
}
for (i = 0; i < EC_LED_COLOR_COUNT; ++i)
printf("\t%s\t: 0x%x\n",
led_color_names[i],
r.brightness_range[i]);
return 0;
}
if (!strcasecmp(argv[2], "off")) {
/* Brightness initialized to 0 for each color. */
} else if (!strcasecmp(argv[2], "auto")) {
p.flags = EC_LED_FLAGS_AUTO;
} else if ((i = find_led_color_by_name(argv[2])) != -1) {
p.brightness[i] = 0xff;
} else {
for (i = 2; i < argc; ++i) {
ptr = strtok(argv[i], "=");
j = find_led_color_by_name(ptr);
if (j == -1) {
fprintf(stderr, "Bad color name: %s\n", ptr);
fprintf(stderr, "Valid colors: ");
for (j = 0; j < EC_LED_COLOR_COUNT; j++)
fprintf(stderr, "%s ",
led_color_names[j]);
fprintf(stderr, "\n");
return -1;
}
ptr = strtok(NULL, "=");
if (ptr == NULL) {
fprintf(stderr, "Missing brightness value\n");
return -1;
}
p.brightness[j] = strtol(ptr, &e, 0);
if (e && *e) {
fprintf(stderr, "Bad brightness: %s\n", ptr);
return -1;
}
}
}
rv = ec_command(EC_CMD_LED_CONTROL, 1, &p, sizeof(p), &r, sizeof(r));
return (rv < 0 ? rv : 0);
}
int cmd_usb_charge_set_mode(int argc, char *argv[])
{
struct ec_params_usb_charge_set_mode p;
char *e;
int rv;
if (argc != 3) {
fprintf(stderr,
"Usage: %s <port_id> <mode_id>\n", argv[0]);
return -1;
}
p.usb_port_id = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad port ID.\n");
return -1;
}
p.mode = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad mode ID.\n");
return -1;
}
printf("Setting port %d to mode %d...\n", p.usb_port_id, p.mode);
rv = ec_command(EC_CMD_USB_CHARGE_SET_MODE, 0,
&p, sizeof(p), NULL, 0);
if (rv < 0)
return rv;
printf("USB charging mode set.\n");
return 0;
}
int cmd_usb_mux(int argc, char *argv[])
{
struct ec_params_usb_mux p;
char *e;
int rv;
if (argc != 2) {
fprintf(stderr, "Usage: %s <mux>\n", argv[0]);
return -1;
}
p.mux = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad mux value.\n");
return -1;
}
rv = ec_command(EC_CMD_USB_MUX, 0,
&p, sizeof(p), NULL, 0);
if (rv < 0)
return rv;
printf("Set USB mux to 0x%x.\n", p.mux);
return 0;
}
int cmd_usb_pd(int argc, char *argv[])
{
const char *role_str[] = {"", "toggle", "toggle-off", "sink", "source"};
const char *mux_str[] = {"", "none", "usb", "dp", "dock"};
struct ec_params_usb_pd_control p;
int rv, i, j;
int option_ok;
char *e;
p.role = USB_PD_CTRL_ROLE_NO_CHANGE;
p.mux = USB_PD_CTRL_MUX_NO_CHANGE;
if (argc <= 2) {
fprintf(stderr, "No option specified.\n");
return -1;
}
p.port = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Invalid param (port)\n");
return -1;
}
for (i = 2; i < argc; ++i) {
option_ok = 0;
if (!strcmp(argv[i], "auto")) {
if (argc != 3) {
fprintf(stderr, "\"auto\" may not be used "
"with other options.\n");
return -1;
}
p.role = USB_PD_CTRL_ROLE_TOGGLE_ON;
p.mux = USB_PD_CTRL_MUX_AUTO;
continue;
}
for (j = 0; j < ARRAY_SIZE(role_str); ++j) {
if (!strcmp(argv[i], role_str[j])) {
if (p.role != USB_PD_CTRL_ROLE_NO_CHANGE) {
fprintf(stderr,
"Only one role allowed.\n");
return -1;
}
p.role = j;
option_ok = 1;
break;
}
}
if (option_ok)
continue;
for (j = 0; j < ARRAY_SIZE(mux_str); ++j) {
if (!strcmp(argv[i], mux_str[j])) {
if (p.mux != USB_PD_CTRL_MUX_NO_CHANGE) {
fprintf(stderr,
"Only one mux type allowed.\n");
return -1;
}
p.mux = j;
option_ok = 1;
break;
}
}
if (!option_ok) {
fprintf(stderr, "Unknown option: %s\n", argv[i]);
return -1;
}
}
rv = ec_command(EC_CMD_USB_PD_CONTROL, 0, &p, sizeof(p), NULL, 0);
return (rv < 0 ? rv : 0);
}
int cmd_kbpress(int argc, char *argv[])
{
struct ec_params_mkbp_simulate_key p;
char *e;
int rv;
if (argc != 4) {
fprintf(stderr,
"Usage: %s <row> <col> <0|1>\n", argv[0]);
return -1;
}
p.row = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad row.\n");
return -1;
}
p.col = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad column.\n");
return -1;
}
p.pressed = strtol(argv[3], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad pressed flag.\n");
return -1;
}
printf("%s row %d col %d.\n", p.pressed ? "Pressing" : "Releasing",
p.row,
p.col);
rv = ec_command(EC_CMD_MKBP_SIMULATE_KEY, 0,
&p, sizeof(p), NULL, 0);
if (rv < 0)
return rv;
printf("Done.\n");
return 0;
}
static void print_panic_reg(int regnum, const uint32_t *regs, int index)
{
static const char * const regname[] = {
"r0 ", "r1 ", "r2 ", "r3 ", "r4 ",
"r5 ", "r6 ", "r7 ", "r8 ", "r9 ",
"r10", "r11", "r12", "sp ", "lr ",
"pc "};
printf("%s:", regname[regnum]);
if (regs)
printf("%08x", regs[index]);
else
printf(" ");
printf((regnum & 3) == 3 ? "\n" : " ");
}
int cmd_panic_info(int argc, char *argv[])
{
int rv;
struct panic_data *pdata = (struct panic_data *)ec_inbuf;
const uint32_t *lregs = pdata->cm.regs;
const uint32_t *sregs = NULL;
enum {
ORIG_UNKNOWN = 0,
ORIG_PROCESS,
ORIG_HANDLER
} origin = ORIG_UNKNOWN;
int i;
const char *panic_origins[3] = {"", "PROCESS", "HANDLER"};
rv = ec_command(EC_CMD_GET_PANIC_INFO, 0, NULL, 0,
ec_inbuf, ec_max_insize);
if (rv < 0)
return rv;
if (rv == 0) {
printf("No panic data.\n");
return 0;
}
/*
* We only understand panic data with version <= 2. Warn the user
* of higher versions.
*/
if (pdata->struct_version > 2)
fprintf(stderr,
"Unknown panic data version (%d). "
"Following data may be incorrect!\n",
pdata->struct_version);
if (pdata->arch != PANIC_ARCH_CORTEX_M)
fprintf(stderr, "Unknown architecture (%d). "
"CPU specific data will be incorrect!\n",
pdata->arch);
printf("Saved panic data:%s\n",
(pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD ? "" : " (NEW)"));
if (pdata->struct_version == 2)
origin = ((lregs[11] & 0xf) == 1 || (lregs[11] & 0xf) == 9) ?
ORIG_HANDLER : ORIG_PROCESS;
/*
* In pdata struct, 'regs', which is allocated before 'frame', has
* one less elements in version 1. Therefore, if the data is from
* version 1, shift 'sregs' by one element to align with 'frame' in
* version 1.
*/
if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID)
sregs = pdata->cm.frame - (pdata->struct_version == 1 ? 1 : 0);
printf("=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n",
panic_origins[origin],
lregs[1] & 0xff, sregs ? sregs[7] : -1);
for (i = 0; i < 4; ++i)
print_panic_reg(i, sregs, i);
for (i = 4; i < 10; ++i)
print_panic_reg(i, lregs, i - 1);
print_panic_reg(10, lregs, 9);
print_panic_reg(11, lregs, 10);
print_panic_reg(12, sregs, 4);
print_panic_reg(13, lregs, origin == ORIG_HANDLER ? 2 : 0);
print_panic_reg(14, sregs, 5);
print_panic_reg(15, sregs, 6);
return 0;
}
int cmd_power_info(int argc, char *argv[])
{
struct ec_response_power_info r;
int rv;
rv = ec_command(EC_CMD_POWER_INFO, 0, NULL, 0, &r, sizeof(r));
if (rv < 0)
return rv;
printf("AC Voltage: %d mV\n", r.voltage_ac);
printf("System Voltage: %d mV\n", r.voltage_system);
printf("System Current: %d mA\n", r.current_system);
printf("System Power: %d mW\n",
r.voltage_system * r.current_system / 1000);
printf("USB Device Type: 0x%x\n", r.usb_dev_type);
printf("USB Current Limit: %d mA\n", r.usb_current_limit);
return 0;
}
int cmd_pstore_info(int argc, char *argv[])
{
struct ec_response_pstore_info r;
int rv;
rv = ec_command(EC_CMD_PSTORE_INFO, 0, NULL, 0, &r, sizeof(r));
if (rv < 0)
return rv;
printf("PstoreSize %d\nAccessSize %d\n", r.pstore_size, r.access_size);
return 0;
}
int cmd_pstore_read(int argc, char *argv[])
{
struct ec_params_pstore_read p;
uint8_t rdata[EC_PSTORE_SIZE_MAX];
int offset, size;
int rv;
int i;
char *e;
char *buf;
if (argc < 4) {
fprintf(stderr,
"Usage: %s <offset> <size> <filename>\n", argv[0]);
return -1;
}
offset = strtol(argv[1], &e, 0);
if ((e && *e) || offset < 0 || offset > 0x10000) {
fprintf(stderr, "Bad offset.\n");
return -1;
}
size = strtol(argv[2], &e, 0);
if ((e && *e) || size <= 0 || size > 0x10000) {
fprintf(stderr, "Bad size.\n");
return -1;
}
printf("Reading %d bytes at offset %d...\n", size, offset);
buf = (char *)malloc(size);
if (!buf) {
fprintf(stderr, "Unable to allocate buffer.\n");
return -1;
}
/* Read data in chunks */
for (i = 0; i < size; i += EC_PSTORE_SIZE_MAX) {
p.offset = offset + i;
p.size = MIN(size - i, EC_PSTORE_SIZE_MAX);
rv = ec_command(EC_CMD_PSTORE_READ, 0,
&p, sizeof(p), rdata, sizeof(rdata));
if (rv < 0) {
fprintf(stderr, "Read error at offset %d\n", i);
free(buf);
return rv;
}
memcpy(buf + i, rdata, p.size);
}
rv = write_file(argv[3], buf, size);
free(buf);
if (rv)
return rv;
printf("done.\n");
return 0;
}
int cmd_pstore_write(int argc, char *argv[])
{
struct ec_params_pstore_write p;
int offset, size;
int rv;
int i;
char *e;
char *buf;
if (argc < 3) {
fprintf(stderr, "Usage: %s <offset> <filename>\n", argv[0]);
return -1;
}
offset = strtol(argv[1], &e, 0);
if ((e && *e) || offset < 0 || offset > 0x10000) {
fprintf(stderr, "Bad offset.\n");
return -1;
}
/* Read the input file */
buf = read_file(argv[2], &size);
if (!buf)
return -1;
printf("Writing to offset %d...\n", offset);
/* Write data in chunks */
for (i = 0; i < size; i += EC_PSTORE_SIZE_MAX) {
p.offset = offset + i;
p.size = MIN(size - i, EC_PSTORE_SIZE_MAX);
memcpy(p.data, buf + i, p.size);
rv = ec_command(EC_CMD_PSTORE_WRITE, 0,
&p, sizeof(p), NULL, 0);
if (rv < 0) {
fprintf(stderr, "Write error at offset %d\n", i);
free(buf);
return rv;
}
}
free(buf);
printf("done.\n");
return 0;
}
int cmd_host_event_get_raw(int argc, char *argv[])
{
uint32_t events = read_mapped_mem32(EC_MEMMAP_HOST_EVENTS);
if (events & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID)) {
printf("Current host events: invalid\n");
return -1;
}
printf("Current host events: 0x%08x\n", events);
return 0;
}
int cmd_host_event_get_b(int argc, char *argv[])
{
struct ec_response_host_event_mask r;
int rv;
rv = ec_command(EC_CMD_HOST_EVENT_GET_B, 0,
NULL, 0, &r, sizeof(r));
if (rv < 0)
return rv;
if (rv < sizeof(r)) {
fprintf(stderr, "Insufficient data received.\n");
return -1;
}
if (r.mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID)) {
printf("Current host events-B: invalid\n");
return -1;
}
printf("Current host events-B: 0x%08x\n", r.mask);
return 0;
}
int cmd_host_event_get_smi_mask(int argc, char *argv[])
{
struct ec_response_host_event_mask r;
int rv;
rv = ec_command(EC_CMD_HOST_EVENT_GET_SMI_MASK, 0,
NULL, 0, &r, sizeof(r));
if (rv < 0)
return rv;
printf("Current host event SMI mask: 0x%08x\n", r.mask);
return 0;
}
int cmd_host_event_get_sci_mask(int argc, char *argv[])
{
struct ec_response_host_event_mask r;
int rv;
rv = ec_command(EC_CMD_HOST_EVENT_GET_SCI_MASK, 0,
NULL, 0, &r, sizeof(r));
if (rv < 0)
return rv;
printf("Current host event SCI mask: 0x%08x\n", r.mask);
return 0;
}
int cmd_host_event_get_wake_mask(int argc, char *argv[])
{
struct ec_response_host_event_mask r;
int rv;
rv = ec_command(EC_CMD_HOST_EVENT_GET_WAKE_MASK, 0,
NULL, 0, &r, sizeof(r));
if (rv < 0)
return rv;
printf("Current host event wake mask: 0x%08x\n", r.mask);
return 0;
}
int cmd_host_event_set_smi_mask(int argc, char *argv[])
{
struct ec_params_host_event_mask p;
char *e;
int rv;
if (argc != 2) {
fprintf(stderr, "Usage: %s <mask>\n", argv[0]);
return -1;
}
p.mask = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad mask.\n");
return -1;
}
rv = ec_command(EC_CMD_HOST_EVENT_SET_SMI_MASK, 0,
&p, sizeof(p), NULL, 0);
if (rv < 0)
return rv;
printf("Mask set.\n");
return 0;
}
int cmd_host_event_set_sci_mask(int argc, char *argv[])
{
struct ec_params