util/comm-i2c: Add switch to specify I2C bus
Currently, devices running CrOS EC that aren't actually the embedded controller (such as touchpad or fingerprint MCUs) can only be contacted over I2C if they are in the device tree. To avoid having to recompile the Kernel, Coreboot, or `ectool`, the `--i2c_bus` switch allows `ectool` to be used for testing as-is. BRANCH=none BUG=none TEST=Checked various commands (hello, version, inventory...) with `--i2c_bus=7`, connecting to a MAX32660. Verified that a contradictory `--interface` switch is rejected. Checked that invalid bus numbers (≥32) are rejected. Change-Id: I92f3307bbbdf88978b9f8271610a3ae222279767 Signed-off-by: Harry Cutts <hcutts@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1828064 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
This commit is contained in:
parent
2ee2d6fe87
commit
5f7e4c337d
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -31,7 +32,7 @@ static int command_offset;
|
|||
|
||||
int comm_init_dev(const char *device_name) __attribute__((weak));
|
||||
int comm_init_lpc(void) __attribute__((weak));
|
||||
int comm_init_i2c(void) __attribute__((weak));
|
||||
int comm_init_i2c(int i2c_bus) __attribute__((weak));
|
||||
int comm_init_servo_spi(const char *device_name) __attribute__((weak));
|
||||
|
||||
static int fake_readmem(int offset, int bytes, void *dest)
|
||||
|
@ -82,8 +83,10 @@ int ec_command(int command, int version,
|
|||
indata, insize);
|
||||
}
|
||||
|
||||
int comm_init_alt(int interfaces, const char *device_name)
|
||||
int comm_init_alt(int interfaces, const char *device_name, int i2c_bus)
|
||||
{
|
||||
bool dev_is_cros_ec;
|
||||
|
||||
/* Default memmap access */
|
||||
ec_readmem = fake_readmem;
|
||||
|
||||
|
@ -93,17 +96,17 @@ int comm_init_alt(int interfaces, const char *device_name)
|
|||
|
||||
/* Do not fallback to other communication methods if target is not a
|
||||
* cros_ec device */
|
||||
if (!strcmp(CROS_EC_DEV_NAME, device_name)) {
|
||||
/* Fallback to direct LPC on x86 */
|
||||
if ((interfaces & COMM_LPC) &&
|
||||
comm_init_lpc && !comm_init_lpc())
|
||||
return 0;
|
||||
dev_is_cros_ec = !strcmp(CROS_EC_DEV_NAME, device_name);
|
||||
|
||||
/* Fallback to direct i2c on ARM */
|
||||
if ((interfaces & COMM_I2C) &&
|
||||
comm_init_i2c && !comm_init_i2c())
|
||||
return 0;
|
||||
}
|
||||
/* Fallback to direct LPC on x86 */
|
||||
if (dev_is_cros_ec && (interfaces & COMM_LPC) &&
|
||||
comm_init_lpc && !comm_init_lpc())
|
||||
return 0;
|
||||
|
||||
/* Fallback to direct I2C */
|
||||
if ((dev_is_cros_ec || i2c_bus != -1) && (interfaces & COMM_I2C) &&
|
||||
comm_init_i2c && !comm_init_i2c(i2c_bus))
|
||||
return 0;
|
||||
|
||||
/* Give up */
|
||||
fprintf(stderr, "Unable to establish host communication\n");
|
||||
|
|
|
@ -39,9 +39,10 @@ enum comm_interface {
|
|||
*
|
||||
* @param interfaces Interfaces to try; use COMM_ALL to try all of them.
|
||||
* @param device_name For DEV option, the device file to use.
|
||||
* @param i2c_bus For I2C option, the bus number to use (or -1 to autodetect).
|
||||
* @return 0 in case of success, or error code.
|
||||
*/
|
||||
int comm_init_alt(int interfaces, const char *device_name);
|
||||
int comm_init_alt(int interfaces, const char *device_name, int i2c_bus);
|
||||
|
||||
/**
|
||||
* Initialize dev interface
|
||||
|
|
|
@ -196,33 +196,44 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int comm_init_i2c(void)
|
||||
int comm_init_i2c(int i2c_bus)
|
||||
{
|
||||
char *file_path;
|
||||
char buffer[64];
|
||||
int i;
|
||||
|
||||
/* find the device number based on the adapter name */
|
||||
for (i = 0; i < I2C_MAX_ADAPTER; i++) {
|
||||
FILE *f;
|
||||
if (asprintf(&file_path, I2C_ADAPTER_NODE,
|
||||
i, i, EC_I2C_ADDR) < 0)
|
||||
if (i2c_bus != -1) {
|
||||
i = i2c_bus;
|
||||
|
||||
if (i >= I2C_MAX_ADAPTER) {
|
||||
fprintf(stderr, "Invalid I2C bus number %d. (The highest possible bus number is %d.)\n",
|
||||
i, I2C_MAX_ADAPTER);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* find the device number based on the adapter name */
|
||||
for (i = 0; i < I2C_MAX_ADAPTER; i++) {
|
||||
FILE *f;
|
||||
|
||||
if (asprintf(&file_path, I2C_ADAPTER_NODE,
|
||||
i, i, EC_I2C_ADDR) < 0)
|
||||
return -1;
|
||||
f = fopen(file_path, "r");
|
||||
if (f) {
|
||||
if (fgets(buffer, sizeof(buffer), f) &&
|
||||
!strncmp(buffer, I2C_ADAPTER_NAME, 6)) {
|
||||
free(file_path);
|
||||
fclose(f);
|
||||
break;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
free(file_path);
|
||||
}
|
||||
if (i == I2C_MAX_ADAPTER) {
|
||||
fprintf(stderr, "Cannot find I2C adapter\n");
|
||||
return -1;
|
||||
f = fopen(file_path, "r");
|
||||
if (f) {
|
||||
if (fgets(buffer, sizeof(buffer), f) &&
|
||||
!strncmp(buffer, I2C_ADAPTER_NAME, 6)) {
|
||||
free(file_path);
|
||||
fclose(f);
|
||||
break;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
free(file_path);
|
||||
}
|
||||
if (i == I2C_MAX_ADAPTER) {
|
||||
fprintf(stderr, "Cannot find I2C adapter\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (asprintf(&file_path, I2C_NODE, i) < 0)
|
||||
|
|
|
@ -48,6 +48,7 @@ enum {
|
|||
OPT_INTERFACE,
|
||||
OPT_NAME,
|
||||
OPT_ASCII,
|
||||
OPT_I2C_BUS,
|
||||
};
|
||||
|
||||
static struct option long_opts[] = {
|
||||
|
@ -55,6 +56,7 @@ static struct option long_opts[] = {
|
|||
{"interface", 1, 0, OPT_INTERFACE},
|
||||
{"name", 1, 0, OPT_NAME},
|
||||
{"ascii", 0, 0, OPT_ASCII},
|
||||
{"i2c_bus", 1, 0, OPT_I2C_BUS},
|
||||
{NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
@ -352,9 +354,13 @@ int parse_bool(const char *s, int *dest)
|
|||
|
||||
void print_help(const char *prog, int print_cmds)
|
||||
{
|
||||
printf("Usage: %s [--dev=n] [--interface=dev|i2c|lpc] ", prog);
|
||||
printf("Usage: %s [--dev=n] [--interface=dev|i2c|lpc] [--i2c_bus=n]",
|
||||
prog);
|
||||
printf("[--name=cros_ec|cros_fp|cros_pd|cros_scp|cros_ish] [--ascii] ");
|
||||
printf("<command> [params]\n\n");
|
||||
printf(" --i2c_bus=n Specifies the number of an I2C bus to use. For\n"
|
||||
" example, to use /dev/i2c-7, pass --i2c_bus=7.\n"
|
||||
" Implies --interface=i2c.\n\n");
|
||||
if (print_cmds)
|
||||
puts(help_str);
|
||||
else
|
||||
|
@ -9156,6 +9162,7 @@ int main(int argc, char *argv[])
|
|||
const struct command *cmd;
|
||||
int dev = 0;
|
||||
int interfaces = COMM_ALL;
|
||||
int i2c_bus = -1;
|
||||
char device_name[41] = CROS_EC_DEV_NAME;
|
||||
int rv = 1;
|
||||
int parse_error = 0;
|
||||
|
@ -9197,12 +9204,29 @@ int main(int argc, char *argv[])
|
|||
strncpy(device_name, optarg, 40);
|
||||
device_name[40] = '\0';
|
||||
break;
|
||||
case OPT_I2C_BUS:
|
||||
i2c_bus = strtoul(optarg, &e, 0);
|
||||
if (*optarg == '\0' || (e && *e != '\0')
|
||||
|| i2c_bus < 0) {
|
||||
fprintf(stderr, "Invalid --i2c_bus\n");
|
||||
parse_error = 1;
|
||||
}
|
||||
break;
|
||||
case OPT_ASCII:
|
||||
ascii_mode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_bus != -1) {
|
||||
if (!(interfaces & COMM_I2C)) {
|
||||
fprintf(stderr, "--i2c_bus is specified, but --interface is set to something other than I2C\n");
|
||||
parse_error = 1;
|
||||
} else {
|
||||
interfaces = COMM_I2C;
|
||||
}
|
||||
}
|
||||
|
||||
/* Must specify a command */
|
||||
if (!parse_error && optind == argc)
|
||||
parse_error = 1;
|
||||
|
@ -9236,7 +9260,7 @@ int main(int argc, char *argv[])
|
|||
fprintf(stderr, "Could not acquire GEC lock.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (comm_init_alt(interfaces, device_name)) {
|
||||
if (comm_init_alt(interfaces, device_name, i2c_bus)) {
|
||||
fprintf(stderr, "Couldn't find EC\n");
|
||||
goto out;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue