| /* 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 <inttypes.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include "anx74xx.h" |
| #include "battery.h" |
| #include "comm-host.h" |
| #include "compile_time_macros.h" |
| #include "ec_panicinfo.h" |
| #include "ec_flash.h" |
| #include "ectool.h" |
| #include "lightbar.h" |
| #include "lock/gec_lock.h" |
| #include "misc_util.h" |
| #include "panic.h" |
| #include "ps8751.h" |
| #include "usb_pd.h" |
| |
| /* Command line options */ |
| enum { |
| OPT_DEV = 1000, |
| OPT_INTERFACE, |
| OPT_NAME, |
| }; |
| |
| static struct option long_opts[] = { |
| {"dev", 1, 0, OPT_DEV}, |
| {"interface", 1, 0, OPT_INTERFACE}, |
| {"name", 1, 0, OPT_NAME}, |
| {NULL, 0, 0, 0} |
| }; |
| |
| #define GEC_LOCK_TIMEOUT_SECS 30 /* 30 secs */ |
| |
| const char help_str[] = |
| "Commands:\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" |
| " chargeoverride\n" |
| " Overrides charge port selection logic\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" |
| " extpwrlimit\n" |
| " Set the maximum external power limit\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" |
| " flashspiinfo\n" |
| " Prints information on EC SPI flash, if present\n" |
| " flashpd <dev_id> <port> <filename>\n" |
| " Flash commands over PD\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" |
| " fpframe\n" |
| " Retrieve the finger image as a PGM image\n" |
| " fpinfo\n" |
| " Prints information about the Fingerprint sensor\n" |
| " fpmode [capture|deepsleep|fingerdown|fingerup]\n" |
| " Configure/Read the fingerprint sensor current mode\n" |
| " forcelidopen <enable>\n" |
| " Forces the lid switch to open position\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" |
| " hibdelay [sec]\n" |
| " Set the delay before going into hibernation\n" |
| " hostsleepstate\n" |
| " Report host sleep state to the EC\n" |
| " kbpress\n" |
| " Simulate key press\n" |
| " kbfactorytest\n" |
| " Scan out keyboard if any pins are shorted\n" |
| " i2cprotect <port> [status]\n" |
| " Protect EC's I2C bus\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" |
| " infopddev <port>\n" |
| " Get info about USB type-C accessory attached to port\n" |
| " inventory\n" |
| " Return the list of supported features\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" |
| " pdcontrol [suspend|resume|reset|disable]\n" |
| " Controls the PD chip\n" |
| " pdchipinfo <port>\n" |
| " Get PD chip information\n" |
| " pdlog\n" |
| " Prints the PD event log entries\n" |
| " pdwritelog <type> <port>\n" |
| " Writes a PD event log of the given <type>\n" |
| " pdgetmode <port>\n" |
| " Get All USB-PD alternate SVIDs and modes on <port>\n" |
| " pdsetmode <port> <svid> <opos>\n" |
| " Set USB-PD alternate SVID and mode on <port>\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" |
| " pwmgetnumfans\n" |
| " Prints the number of fans present\n" |
| " pwmgetduty\n" |
| " Prints the current 16 bit duty cycle for given PWM\n" |
| " pwmsetfanrpm <targetrpm>\n" |
| " Set target fan RPM\n" |
| " pwmsetkblight <percent>\n" |
| " Set keyboard backlight in percent\n" |
| " pwmsetduty\n" |
| " Set 16 bit duty cycle of given PWM\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" |
| " rtcgetalarm\n" |
| " Print # of seconds before real-time clock alarm goes off.\n" |
| " rtcset <time>\n" |
| " Set real-time clock\n" |
| " rtcsetalarm <sec>\n" |
| " Set real-time clock alarm to go off in <sec> seconds\n" |
| " rwhashpd <dev_id> <HASH[0] ... <HASH[4]>\n" |
| " Set entry in PD MCU's device rw_hash table.\n" |
| " rwsigaction\n" |
| " Control the behavior of RWSIG task.\n" |
| " rwsigstatus\n" |
| " Run RW signature verification and get status.\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" |
| " tpselftest\n" |
| " Run touchpad self test.\n" |
| " tpframeget\n" |
| " Get touchpad frame data.\n" |
| " tmp006cal <tmp006_index> [params...]\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] " |
| "[dr_swap|pr_swap|vconn_swap]>\n" |
| " Control USB PD/type-C\n" |
| " usbpdmuxinfo\n" |
| " Get USB-C SS mux info\n" |
| " usbpdpower\n" |
| " Get USB PD power information\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[] = { |
| "red", "green", "blue", "yellow", "white", "amber"}; |
| BUILD_ASSERT(ARRAY_SIZE(led_color_names) == EC_LED_COLOR_COUNT); |
| |
| /* Note: depends on enum ec_led_id */ |
| static const char * const led_names[] = { |
| "battery", "power", "adapter", "left", "right", "recovery_hwreinit"}; |
| BUILD_ASSERT(ARRAY_SIZE(led_names) == EC_LED_ID_COUNT); |
| |
| /* 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] ", prog); |
| printf("[--name=cros_ec|cros_sh|cros_pd] <command> [params]\n\n"); |
| 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_hibdelay(int argc, char *argv[]) |
| { |
| struct ec_params_hibernation_delay p; |
| struct ec_response_hibernation_delay r; |
| char *e; |
| int rv; |
| |
| if (argc < 2) { |
| p.seconds = 0; /* Just read the current settings. */ |
| } else { |
| p.seconds = strtoul(argv[1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "invalid number\n"); |
| return -1; |
| } |
| } |
| |
| rv = ec_command(EC_CMD_HIBERNATION_DELAY, 0, &p, sizeof(p), |
| &r, sizeof(r)); |
| if (rv < 0) { |
| fprintf(stderr, "err: rv=%d\n", rv); |
| return -1; |
| } |
| |
| printf("Hibernation delay: %u s\n", r.hibernate_delay); |
| printf("Time G3: %u s\n", r.time_g3); |
| printf("Time left: %u s\n", r.time_remaining); |
| return 0; |
| } |
| |
| int cmd_hostsleepstate(int argc, char *argv[]) |
| { |
| struct ec_params_host_sleep_event p; |
| |
| if (argc < 2) { |
| fprintf(stderr, "Usage: %s [suspend|resume|freeze|thaw]\n", |
| argv[0]); |
| return -1; |
| } |
| |
| if (!strcmp(argv[1], "suspend")) |
| p.sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND; |
| else if (!strcmp(argv[1], "resume")) |
| p.sleep_event = HOST_SLEEP_EVENT_S3_RESUME; |
| else if (!strcmp(argv[1], "freeze")) |
| p.sleep_event = HOST_SLEEP_EVENT_S0IX_SUSPEND; |
| else if (!strcmp(argv[1], "thaw")) |
| p.sleep_event = HOST_SLEEP_EVENT_S0IX_RESUME; |
| else { |
| fprintf(stderr, "Unknown command: %s\n", argv[1]); |
| return -1; |
| } |
| |
| return ec_command(EC_CMD_HOST_SLEEP_EVENT, 0, &p, sizeof(p), NULL, 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, param; |
| |
| p.flags = 0; |
| |
| if (argc > 1) { |
| p.flags |= EC_GSV_SET; |
| if (!parse_bool(argv[1], ¶m)) { |
| fprintf(stderr, "invalid arg \"%s\"\n", argv[1]); |
| return -1; |
| } |
| p.value = param; |
| } |
| |
| 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; |
| } |
| |
| static const char * const ec_feature_names[] = { |
| [EC_FEATURE_LIMITED] = "Limited image, load RW for more", |
| [EC_FEATURE_FLASH] = "Flash", |
| [EC_FEATURE_PWM_FAN] = "Direct Fan power management", |
| [EC_FEATURE_PWM_KEYB] = "Keyboard backlight", |
| [EC_FEATURE_LIGHTBAR] = "Lightbar", |
| [EC_FEATURE_LED] = "LED", |
| [EC_FEATURE_MOTION_SENSE] = "Motion Sensors", |
| [EC_FEATURE_KEYB] = "Keyboard", |
| [EC_FEATURE_PSTORE] = "Host Permanent Storage", |
| [EC_FEATURE_PORT80] = "BIOS Port 80h access", |
| [EC_FEATURE_THERMAL] = "Thermal management", |
| [EC_FEATURE_BKLIGHT_SWITCH] = "Switch backlight on/off", |
| [EC_FEATURE_WIFI_SWITCH] = "Switch wifi on/off", |
| [EC_FEATURE_HOST_EVENTS] = "Host event", |
| [EC_FEATURE_GPIO] = "GPIO", |
| [EC_FEATURE_I2C] = "I2C master", |
| [EC_FEATURE_CHARGER] = "Charger", |
| [EC_FEATURE_BATTERY] = "Simple Battery", |
| [EC_FEATURE_SMART_BATTERY] = "Smart Battery", |
| [EC_FEATURE_HANG_DETECT] = "Host hang detection", |
| [EC_FEATURE_PMU] = "Power Management", |
| [EC_FEATURE_SUB_MCU] = "Control downstream MCU", |
| [EC_FEATURE_USB_PD] = "USB Cros Power Delievery", |
| [EC_FEATURE_USB_MUX] = "USB Multiplexer", |
| [EC_FEATURE_MOTION_SENSE_FIFO] = "FIFO for Motion Sensors events", |
| [EC_FEATURE_VSTORE] = "Temporary secure vstore", |
| [EC_FEATURE_USBC_SS_MUX_VIRTUAL] = "Host-controlled USB-C SS mux", |
| [EC_FEATURE_RTC] = "Real-time clock", |
| [EC_FEATURE_TOUCHPAD] = "Touchpad", |
| [EC_FEATURE_RWSIG] = "RWSIG task", |
| }; |
| |
| int cmd_inventory(int argc, char *argv[]) |
| { |
| struct ec_response_get_features r; |
| int rv, i, j, idx; |
| |
| rv = ec_command(EC_CMD_GET_FEATURES, 0, NULL, 0, &r, sizeof(r)); |
| if (rv < 0) |
| return rv; |
| |
| printf("EC supported features:\n"); |
| for (i = 0, idx = 0; i < 2; i++) { |
| for (j = 0; j < 32; j++, idx++) { |
| if (r.flags[i] & (1 << j)) { |
| if (idx >= ARRAY_SIZE(ec_feature_names) || |
| strlen(ec_feature_names[idx]) == 0) |
| printf("%-4d: Unknown feature\n", idx); |
| else |
| printf("%-4d: %s support\n", |
| idx, ec_feature_names[idx]); |
| } |
| } |
| } |
| return 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_spi_info(int argc, char *argv[]) |
| { |
| struct ec_response_flash_spi_info r; |
| int rv; |
| |
| memset(&r, 0, sizeof(r)); |
| |
| /* Print SPI flash info if available */ |
| if (!ec_cmd_version_supported(EC_CMD_FLASH_SPI_INFO, 0)) { |
| printf("EC has no info (does not use SPI flash?)\n"); |
| return -1; |
| } |
| |
| rv = ec_command(EC_CMD_FLASH_SPI_INFO, 0, NULL, 0, &r, sizeof(r)); |
| if (rv < 0) |
| return rv; |
| |
| printf("JEDECManufacturerID 0x%02x\n", r.jedec[0]); |
| printf("JEDECDeviceID 0x%02x 0x%02x\n", r.jedec[1], r.jedec[2]); |
| printf("JEDECCapacity %d\n", 1 << r.jedec[2]); |
| printf("ManufacturerID 0x%02x\n", r.mfr_dev_id[0]); |
| printf("DeviceID 0x%02x\n", r.mfr_dev_id[1]); |
| printf("StatusRegister1 0x%02x\n", r.sr1); |
| printf("StatusRegister2 0x%02x\n", r.sr2); |
| 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_RW_AT_BOOT) |
| printf(" rw_at_boot"); |
| if (flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) |
| printf(" rollback_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_RW_NOW) |
| printf(" rw_now"); |
| if (flags & EC_FLASH_PROTECT_ROLLBACK_NOW) |
| printf(" rollback_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_rw_hash_pd(int argc, char *argv[]) |
| { |
| struct ec_params_usb_pd_rw_hash_entry *p = |
| (struct ec_params_usb_pd_rw_hash_entry *)ec_outbuf; |
| int i, rv; |
| char *e; |
| uint32_t val; |
| uint8_t *rwp; |
| |
| if (argc < 7) { |
| fprintf(stderr, "Usage: %s <dev_id> <HASH[0]> ... <HASH[4]>\n", |
| argv[0]); |
| return -1; |
| } |
| |
| p->dev_id = strtol(argv[1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad device ID\n"); |
| return -1; |
| } |
| |
| rwp = p->dev_rw_hash; |
| for (i = 2; i < 7; i++) { |
| val = strtol(argv[i], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad RW hash\n"); |
| return -1; |
| } |
| rwp[0] = (uint8_t) (val >> 0) & 0xff; |
| rwp[1] = (uint8_t) (val >> 8) & 0xff; |
| rwp[2] = (uint8_t) (val >> 16) & 0xff; |
| rwp[3] = (uint8_t) (val >> 24) & 0xff; |
| rwp += 4; |
| } |
| rv = ec_command(EC_CMD_USB_PD_RW_HASH_ENTRY, 0, p, sizeof(*p), NULL, 0); |
| |
| return rv; |
| } |
| |
| int cmd_rwsig_status(int argc, char *argv[]) |
| { |
| int rv; |
| struct ec_response_rwsig_check_status resp; |
| |
| rv = ec_command(EC_CMD_RWSIG_CHECK_STATUS, 0, NULL, 0, |
| &resp, sizeof(resp)); |
| if (rv < 0) |
| return rv; |
| |
| printf("RW signature check: %s\n", resp.status ? "OK" : "FAILED"); |
| |
| return 0; |
| } |
| |
| int cmd_rwsig_action(int argc, char *argv[]) |
| { |
| struct ec_params_rwsig_action req; |
| |
| if (argc < 2) { |
| fprintf(stderr, "Usage: %s abort | continue\n", argv[0]); |
| return -1; |
| } |
| |
| if (!strcasecmp(argv[1], "abort")) |
| req.action = RWSIG_ACTION_ABORT; |
| else if (!strcasecmp(argv[1], "continue")) |
| req.action = RWSIG_ACTION_CONTINUE; |
| else |
| return -1; |
| |
| return ec_command(EC_CMD_RWSIG_ACTION, 0, &req, sizeof(req), NULL, 0); |
| } |
| |
| int cmd_fp_mode(int argc, char *argv[]) |
| { |
| struct ec_params_fp_mode p; |
| struct ec_response_fp_mode r; |
| uint32_t mode = 0; |
| int i, rv; |
| |
| if (argc == 1) |
| mode = FP_MODE_DONT_CHANGE; |
| for (i = 1; i < argc; i++) { |
| if (!strncmp(argv[i], "deepsleep", 9)) |
| mode |= FP_MODE_DEEPSLEEP; |
| else if (!strncmp(argv[i], "fingerdown", 10)) |
| mode |= FP_MODE_FINGER_DOWN; |
| else if (!strncmp(argv[i], "fingerup", 8)) |
| mode |= FP_MODE_FINGER_UP; |
| else if (!strncmp(argv[i], "capture", 7)) |
| mode |= FP_MODE_CAPTURE; |
| } |
| |
| p.mode = mode; |
| rv = ec_command(EC_CMD_FP_MODE, 0, &p, sizeof(p), &r, sizeof(r)); |
| if (rv < 0) |
| return rv; |
| |
| printf("FP mode: (0x%x) ", r.mode); |
| if (r.mode & FP_MODE_DEEPSLEEP) |
| printf("deepsleep "); |
| if (r.mode & FP_MODE_FINGER_DOWN) |
| printf("finger-down "); |
| if (r.mode & FP_MODE_FINGER_UP) |
| printf("finger-up "); |
| if (r.mode & FP_MODE_CAPTURE) |
| printf("capture "); |
| printf("\n"); |
| return rv; |
| } |
| |
| int cmd_fp_info(int argc, char *argv[]) |
| { |
| struct ec_response_fp_info r; |
| int rv; |
| |
| rv = ec_command(EC_CMD_FP_INFO, 0, NULL, 0, &r, sizeof(r)); |
| if (rv < 0) |
| return rv; |
| |
| printf("Fingerprint sensor: vendor %x product %x model %x version %x\n", |
| r.vendor_id, r.product_id, r.model_id, r.version); |
| printf("Image: size %dx%d %d bpp\n", r.width, r.height, r.bpp); |
| |
| return 0; |
| } |
| |
| int cmd_fp_frame(int argc, char *argv[]) |
| { |
| struct ec_response_fp_info r; |
| struct ec_params_fp_frame p; |
| int rv = 0; |
| size_t stride, size; |
| uint8_t *buffer8 = ec_inbuf; |
| |
| rv = ec_command(EC_CMD_FP_INFO, 0, NULL, 0, &r, sizeof(r)); |
| if (rv < 0) |
| return rv; |
| |
| stride = (size_t)r.width * r.bpp/8; |
| if (stride > ec_max_insize) { |
| fprintf(stderr, "Not implemented for line size %zu B " |
| "(%u pixels) > EC transfer size %d\n", |
| stride, r.width, ec_max_insize); |
| return -1; |
| } |
| if (r.bpp != 8) { |
| fprintf(stderr, "Not implemented for BPP = %d != 8\n", r.bpp); |
| return -1; |
| } |
| |
| size = stride * r.height; |
| |
| /* Print 8-bpp PGM ASCII header */ |
| printf("P2\n%d %d\n%d\n", r.width, r.height, (1 << r.bpp) - 1); |
| |
| p.offset = 0; |
| p.size = stride; |
| while (size) { |
| int x; |
| |
| rv = ec_command(EC_CMD_FP_FRAME, 0, &p, sizeof(p), |
| ec_inbuf, stride); |
| if (rv < 0) |
| return rv; |
| p.offset += stride; |
| size -= stride; |
| |
| for (x = 0; x < stride; x++) |
| printf("%d ", buffer8[x]); |
| printf("\n"); |
| } |
| printf("# END OF FILE\n"); |
| |
| return 0; |
| } |
| |
| /** |
| * determine if in GFU mode or not. |
| * |
| * NOTE, Sends HOST commands that modify ec_outbuf contents. |
| * |
| * @opos return value of GFU mode object position or zero if not found |
| * @port port number to query |
| * @return 1 if in GFU mode, 0 if not, -1 if error |
| */ |
| static int in_gfu_mode(int *opos, int port) |
| { |
| int i; |
| struct ec_params_usb_pd_get_mode_request *p = |
| (struct ec_params_usb_pd_get_mode_request *)ec_outbuf; |
| struct ec_params_usb_pd_get_mode_response *r = |
| (struct ec_params_usb_pd_get_mode_response *)ec_inbuf; |
| p->port = port; |
| p->svid_idx = 0; |
| do { |
| ec_command(EC_CMD_USB_PD_GET_AMODE, 0, p, sizeof(*p), |
| ec_inbuf, ec_max_insize); |
| if (!r->svid || (r->svid == USB_VID_GOOGLE)) |
| break; |
| p->svid_idx++; |
| } while (p->svid_idx < SVID_DISCOVERY_MAX); |
| |
| if (r->svid != USB_VID_GOOGLE) { |
| fprintf(stderr, "Google VID not returned\n"); |
| return -1; |
| } |
| |
| *opos = 0; /* invalid ... must be 1 thru 6 */ |
| for (i = 0; i < PDO_MODES; i++) { |
| if (r->vdo[i] == MODE_GOOGLE_FU) { |
| *opos = i + 1; |
| break; |
| } |
| } |
| |
| return r->opos == *opos; |
| } |
| |
| /** |
| * Enter GFU mode. |
| * |
| * NOTE, Sends HOST commands that modify ec_outbuf contents. |
| * |
| * @port port number to enter GFU on. |
| * @return 1 if entered GFU mode, 0 if not, -1 if error |
| */ |
| static int enter_gfu_mode(int port) |
| { |
| int opos; |
| struct ec_params_usb_pd_set_mode_request *p = |
| (struct ec_params_usb_pd_set_mode_request *)ec_outbuf; |
| int gfu_mode = in_gfu_mode(&opos, port); |
| |
| if (gfu_mode < 0) { |
| fprintf(stderr, "Failed to query GFU mode support\n"); |
| return 0; |
| } else if (!gfu_mode) { |
| if (!opos) { |
| fprintf(stderr, "Invalid object position %d\n", opos); |
| return 0; |
| } |
| p->port = port; |
| p->svid = USB_VID_GOOGLE; |
| p->opos = opos; |
| p->cmd = PD_ENTER_MODE; |
| |
| ec_command(EC_CMD_USB_PD_SET_AMODE, 0, p, sizeof(*p), |
| NULL, 0); |
| usleep(500000); /* sleep to allow time for set mode */ |
| gfu_mode = in_gfu_mode(&opos, port); |
| } |
| return gfu_mode; |
| } |
| |
| int cmd_pd_device_info(int argc, char *argv[]) |
| { |
| int i, rv, port; |
| char *e; |
| struct ec_params_usb_pd_info_request *p = |
| (struct ec_params_usb_pd_info_request *)ec_outbuf; |
| struct ec_params_usb_pd_rw_hash_entry *r0 = |
| (struct ec_params_usb_pd_rw_hash_entry *)ec_inbuf; |
| struct ec_params_usb_pd_discovery_entry *r1; |
| |
| if (argc < 2) { |
| fprintf(stderr, "Usage: %s <port>\n", argv[0]); |
| return -1; |
| } |
| |
| port = strtol(argv[1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad port\n"); |
| return -1; |
| } |
| |
| p->port = port; |
| r1 = (struct ec_params_usb_pd_discovery_entry *)ec_inbuf; |
| rv = ec_command(EC_CMD_USB_PD_DISCOVERY, 0, p, sizeof(*p), |
| ec_inbuf, ec_max_insize); |
| if (rv < 0) |
| return rv; |
| |
| if (!r1->vid) |
| printf("Port:%d has no discovered device\n", port); |
| else { |
| printf("Port:%d ptype:%d vid:0x%04x pid:0x%04x\n", port, |
| r1->ptype, r1->vid, r1->pid); |
| } |
| |
| if (enter_gfu_mode(port) != 1) { |
| fprintf(stderr, "Failed to enter GFU mode\n"); |
| return -1; |
| } |
| |
| p->port = port; |
| rv = ec_command(EC_CMD_USB_PD_DEV_INFO, 0, p, sizeof(*p), |
| ec_inbuf, ec_max_insize); |
| if (rv < 0) |
| return rv; |
| |
| if (!r0->dev_id) |
| printf("Port:%d has no valid device\n", port); |
| else { |
| uint8_t *rwp = r0->dev_rw_hash; |
| printf("Port:%d DevId:%d.%d Hash:", port, |
| HW_DEV_ID_MAJ(r0->dev_id), HW_DEV_ID_MIN(r0->dev_id)); |
| for (i = 0; i < 5; i++) { |
| printf(" 0x%02x%02x%02x%02x", rwp[3], rwp[2], rwp[1], |
| rwp[0]); |
| rwp += 4; |
| } |
| printf(" CurImg:%s\n", image_names[r0->current_image]); |
| } |
| |
| return rv; |
| } |
| |
| int cmd_flash_pd(int argc, char *argv[]) |
| { |
| struct ec_params_usb_pd_fw_update *p = |
| (struct ec_params_usb_pd_fw_update *)ec_outbuf; |
| int i, dev_id, port; |
| int rv, fsize, step = 96; |
| char *e; |
| char *buf; |
| char *data = (char *)p + sizeof(*p); |
| |
| if (argc < 4) { |
| fprintf(stderr, "Usage: %s <dev_id> <port> <filename>\n", |
| argv[0]); |
| return -1; |
| } |
| |
| dev_id = strtol(argv[1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad device ID\n"); |
| return -1; |
| } |
| |
| port = strtol(argv[2], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad port\n"); |
| return -1; |
| } |
| |
| if (enter_gfu_mode(port) != 1) { |
| fprintf(stderr, "Failed to enter GFU mode\n"); |
| return -1; |
| } |
| |
| /* Read the input file */ |
| buf = read_file(argv[3], &fsize); |
| if (!buf) |
| return -1; |
| |
| /* Erase the current RW RSA signature */ |
| fprintf(stderr, "Erasing expected RW hash\n"); |
| p->dev_id = dev_id; |
| p->port = port; |
| p->cmd = USB_PD_FW_ERASE_SIG; |
| p->size = 0; |
| rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, |
| p, p->size + sizeof(*p), NULL, 0); |
| |
| if (rv < 0) |
| goto pd_flash_error; |
| |
| /* Reboot */ |
| fprintf(stderr, "Rebooting\n"); |
| p->dev_id = dev_id; |
| p->port = port; |
| p->cmd = USB_PD_FW_REBOOT; |
| p->size = 0; |
| rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, |
| p, p->size + sizeof(*p), NULL, 0); |
| |
| if (rv < 0) |
| goto pd_flash_error; |
| |
| usleep(3000000); /* 3sec to reboot and get CC line idle */ |
| |
| /* re-enter GFU after reboot */ |
| if (enter_gfu_mode(port) != 1) { |
| fprintf(stderr, "Failed to enter GFU mode\n"); |
| goto pd_flash_error; |
| } |
| |
| /* Erase RW flash */ |
| fprintf(stderr, "Erasing RW flash\n"); |
| p->dev_id = dev_id; |
| p->port = port; |
| p->cmd = USB_PD_FW_FLASH_ERASE; |
| p->size = 0; |
| rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, |
| p, p->size + sizeof(*p), NULL, 0); |
| |
| /* 3 secs should allow ample time for 2KB page erases at 40ms */ |
| usleep(3000000); |
| |
| if (rv < 0) |
| goto pd_flash_error; |
| |
| /* Write RW flash */ |
| fprintf(stderr, "Writing RW flash\n"); |
| p->dev_id = dev_id; |
| p->port = port; |
| p->cmd = USB_PD_FW_FLASH_WRITE; |
| p->size = step; |
| |
| for (i = 0; i < fsize; i += step) { |
| p->size = MIN(fsize - i, step); |
| memcpy(data, buf + i, p->size); |
| rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, |
| p, p->size + sizeof(*p), NULL, 0); |
| if (rv < 0) |
| goto pd_flash_error; |
| |
| /* |
| * TODO(crosbug.com/p/33905) throttle so EC doesn't watchdog on |
| * other tasks. Remove once issue resolved. |
| */ |
| usleep(10000); |
| } |
| |
| /* 100msec to guarantee writes finish */ |
| usleep(100000); |
| |
| /* Reboot into new RW */ |
| fprintf(stderr, "Rebooting PD into new RW\n"); |
| p->cmd = USB_PD_FW_REBOOT; |
| p->size = 0; |
| rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, |
| p, p->size + sizeof(*p), NULL, 0); |
| |
| if (rv < 0) |
| goto pd_flash_error; |
| |
| free(buf); |
| fprintf(stderr, "Complete\n"); |
| return 0; |
| |
| pd_flash_error: |
| free(buf); |
| fprintf(stderr, "PD flash error\n"); |
| return -1; |
| } |
| |
| int cmd_pd_set_amode(int argc, char *argv[]) |
| { |
| char *e; |
| struct ec_params_usb_pd_set_mode_request *p = |
| (struct ec_params_usb_pd_set_mode_request *)ec_outbuf; |
| |
| if (argc < 5) { |
| fprintf(stderr, "Usage: %s <port> <svid> <opos> <cmd>\n", |
| argv[0]); |
| return -1; |
| } |
| |
| p->port = strtol(argv[1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad port\n"); |
| return -1; |
| } |
| |
| p->svid = strtol(argv[2], &e, 0); |
| if ((e && *e) || !p->svid) { |
| fprintf(stderr, "Bad svid\n"); |
| return -1; |
| } |
| |
| p->opos = strtol(argv[3], &e, 0); |
| if ((e && *e) || !p->opos) { |
| fprintf(stderr, "Bad opos\n"); |
| return -1; |
| } |
| |
| p->cmd = strtol(argv[4], &e, 0); |
| if ((e && *e) || (p->cmd >= PD_MODE_CMD_COUNT)) { |
| fprintf(stderr, "Bad cmd\n"); |
| return -1; |
| } |
| return ec_command(EC_CMD_USB_PD_SET_AMODE, 0, p, sizeof(*p), NULL, 0); |
| } |
| |
| int cmd_pd_get_amode(int argc, char *argv[]) |
| { |
| int i; |
| char *e; |
| struct ec_params_usb_pd_get_mode_request *p = |
| (struct ec_params_usb_pd_get_mode_request *)ec_outbuf; |
| struct ec_params_usb_pd_get_mode_response *r = |
| (struct ec_params_usb_pd_get_mode_response *)ec_inbuf; |
| |
| if (argc < 2) { |
| fprintf(stderr, "Usage: %s <port>\n", argv[0]); |
| return -1; |
| } |
| |
| p->port = strtol(argv[1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad port\n"); |
| return -1; |
| } |
| |
| p->svid_idx = 0; |
| do { |
| ec_command(EC_CMD_USB_PD_GET_AMODE, 0, p, sizeof(*p), |
| ec_inbuf, ec_max_insize); |
| if (!r->svid) |
| break; |
| printf("%cSVID:0x%04x ", (r->opos) ? '*' : ' ', |
| r->svid); |
| for (i = 0; i < PDO_MODES; i++) { |
| printf("%c0x%08x ", (r->opos && (r->opos == i + 1)) ? |
| '*' : ' ', r->vdo[i]); |
| } |
| printf("\n"); |
| p->svid_idx++; |
| } while (p->svid_idx < SVID_DISCOVERY_MAX); |
| return -1; |
| } |
| |
| /* The I/O asm funcs exist only on x86. */ |
| #if defined(__i386__) || defined(__x86_64__) |
| #include <sys/io.h> |
| |
| 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 cmd_port_80_flood(int argc, char *argv[]) |
| { |
| int i; |
| |
| for (i = 0; i < 256; i++) |
| outb(i, 0x80); |
| return 0; |
| } |
| #else |
| int cmd_serial_test(int argc, char *argv[]) |
| { |
| printf("x86 specific command\n"); |
| return -1; |
| } |
| |
| int cmd_port_80_flood(int argc, char *argv[]) |
| { |
| printf("x86 specific command\n"); |
| return -1; |
| } |
| #endif |
| |
| 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++) { |
| if (read_mapped_temperature(p.id) == |
| EC_TEMP_SENSOR_NOT_PRESENT) |
| continue; |
| 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; |
| |
| 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; |
| } |
| |
| int cmd_thermal_get_threshold(int argc, char *argv[]) |
| { |
| if (ec_cmd_version_supported(EC_CMD_THERMAL_GET_THRESHOLD, 1)) |
| return cmd_thermal_get_threshold_v1(argc, argv); |
| else if (ec_cmd_version_supported(EC_CMD_THERMAL_GET_THRESHOLD, 0)) |
| return cmd_thermal_get_threshold_v0(argc, argv); |
| |
| printf("I got nuthin.\n"); |
| return -1; |
| } |
| |
| int cmd_thermal_set_threshold(int argc, char *argv[]) |
| { |
| if (ec_cmd_version_supported(EC_CMD_THERMAL_SET_THRESHOLD, 1)) |
| return cmd_thermal_set_threshold_v1(argc, argv); |
| else if (ec_cmd_version_supported(EC_CMD_THERMAL_SET_THRESHOLD, 0)) |
| return cmd_thermal_set_threshold_v0(argc, argv); |
| |
| printf("I got nuthin.\n"); |
| return -1; |
| } |
| |
| |
| static int get_num_fans(void) |
| { |
| int idx, rv; |
| struct ec_response_get_features r; |
| |
| /* |
| * iff the EC supports the GET_FEATURES, |
| * check whether it has fan support enabled. |
| */ |
| rv = ec_command(EC_CMD_GET_FEATURES, 0, NULL, 0, &r, sizeof(r)); |
| if (rv == EC_SUCCESS && !(r.flags[0] & (1 << EC_FEATURE_PWM_FAN))) |
| return 0; |
| |
| for (idx = 0; idx < EC_FAN_SPEED_ENTRIES; idx++) { |
| rv = read_mapped_mem16(EC_MEMMAP_FAN + 2 * idx); |
| if (rv == EC_FAN_SPEED_NOT_PRESENT) |
| break; |
| } |
| |
| return idx; |
| } |
| |
| int cmd_thermal_auto_fan_ctrl(int argc, char *argv[]) |
| { |
| int rv, num_fans; |
| struct ec_params_auto_fan_ctrl_v1 p_v1; |
| char *e; |
| int cmdver = 1; |
| |
| if (!ec_cmd_version_supported(EC_CMD_THERMAL_AUTO_FAN_CTRL, cmdver) |
| || (argc == 1)) { |
| /* If no argument is provided then enable auto fan ctrl */ |
| /* for all fans by using version 0 of the host command */ |
| |
| 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 for all fans.\n"); |
| return 0; |
| } |
| |
| if (argc > 2 || !strcmp(argv[1], "help")) { |
| printf("Usage: %s [idx]\n", argv[0]); |
| return -1; |
| } |
| |
| num_fans = get_num_fans(); |
| p_v1.fan_idx = strtol(argv[1], &e, 0); |
| if ((e && *e) || (p_v1.fan_idx >= num_fans)) { |
| fprintf(stderr, "Bad fan index.\n"); |
| return -1; |
| } |
| |
| rv = ec_command(EC_CMD_THERMAL_AUTO_FAN_CTRL, cmdver, |
| &p_v1, sizeof(p_v1), NULL, 0); |
| if (rv < 0) |
| return rv; |
| |
| printf("Automatic fan control is now on for fan %d\n", p_v1.fan_idx); |
| |
| 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_num_fans(int argc, char *argv[]) |
| { |
| int num_fans; |
| |
| num_fans = get_num_fans(); |
| |
| printf("Number of fans = %d\n", num_fans); |
| |
| return 0; |
| } |
| |
| int cmd_pwm_get_fan_rpm(int argc, char *argv[]) |
| { |
| int i, num_fans; |
| |
| num_fans = get_num_fans(); |
| if (argc < 2 || !strcasecmp(argv[1], "all")) { |
| /* Print all the fan speeds */ |
| for (i = 0; i < num_fans; i++) |
| print_fan(i); |
| } else { |
| char *e; |
| int idx; |
| |
| idx = strtol(argv[1], &e, 0); |
| if ((e && *e) || idx < 0 || idx >= num_fans) { |
| fprintf(stderr, "Bad index.\n"); |
| return -1; |
| } |
| |
| print_fan(idx); |
| } |
| |
| return 0; |
| } |
| |
| |
| int cmd_pwm_set_fan_rpm(int argc, char *argv[]) |
| { |
| struct ec_params_pwm_set_fan_target_rpm_v1 p_v1; |
| char *e; |
| int rv, num_fans; |
| int cmdver = 1; |
| |
| if (!ec_cmd_version_supported(EC_CMD_PWM_SET_FAN_TARGET_RPM, cmdver)) { |
| struct ec_params_pwm_set_fan_target_rpm_v0 p_v0; |
| |
| /* Fall back to command version 0 command */ |
| cmdver = 0; |
| |
| if (argc != 2) { |
| fprintf(stderr, |
| "Usage: %s <targetrpm>\n", argv[0]); |
| return -1; |
| } |
| p_v0.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, cmdver, |
| &p_v0, sizeof(p_v0), NULL, 0); |
| if (rv < 0) |
| return rv; |
| |
| printf("Fan target RPM set for all fans.\n"); |
| return 0; |
| } |
| |
| if (argc > 3 || (argc == 2 && !strcmp(argv[1], "help")) || argc == 1) { |
| printf("Usage: %s [idx] <targetrpm>\n", argv[0]); |
| printf("'%s 0 3000' - Set fan 0 RPM to 3000\n", argv[0]); |
| printf("'%s 3000' - Set all fans RPM to 3000\n", argv[0]); |
| return -1; |
| } |
| |
| num_fans = get_num_fans(); |
| p_v1.rpm = strtol(argv[argc - 1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad RPM.\n"); |
| return -1; |
| } |
| |
| if (argc == 2) { |
| /* Reuse version 0 command if we're setting targetrpm |
| * for all fans */ |
| struct ec_params_pwm_set_fan_target_rpm_v0 p_v0; |
| |
| cmdver = 0; |
| p_v0.rpm = p_v1.rpm; |
| |
| rv = ec_command(EC_CMD_PWM_SET_FAN_TARGET_RPM, cmdver, |
| &p_v0, sizeof(p_v0), NULL, 0); |
| if (rv < 0) |
| return rv; |
| |
| printf("Fan target RPM set for all fans.\n"); |
| } else { |
| p_v1.fan_idx = strtol(argv[1], &e, 0); |
| if ((e && *e) || (p_v1.fan_idx >= num_fans)) { |
| fprintf(stderr, "Bad fan index.\n"); |
| return -1; |
| } |
| |
| rv = ec_command(EC_CMD_PWM_SET_FAN_TARGET_RPM, cmdver, |
| &p_v1, sizeof(p_v1), NULL, 0); |
| if (rv < 0) |
| return rv; |
| |
| printf("Fan %d target RPM set.\n", p_v1.fan_idx); |
| } |
| |
| 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_pwm_get_duty(int argc, char *argv[]) |
| { |
| struct ec_params_pwm_get_duty p; |
| struct ec_response_pwm_get_duty r; |
| char *e; |
| int rv; |
| |
| if (argc != 2) { |
| fprintf(stderr, "Usage: %s <pwm_idx> | kb | disp\n", argv[0]); |
| return -1; |
| } |
| |
| if (!strcmp(argv[1], "kb")) { |
| p.pwm_type = EC_PWM_TYPE_KB_LIGHT; |
| p.index = 0; |
| } else if (!strcmp(argv[1], "disp")) { |
| p.pwm_type = EC_PWM_TYPE_DISPLAY_LIGHT; |
| p.index = 0; |
| } else { |
| p.pwm_type = EC_PWM_TYPE_GENERIC; |
| p.index = strtol(argv[1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad pwm_idx\n"); |
| return -1; |
| } |
| } |
| |
| rv = ec_command(EC_CMD_PWM_GET_DUTY, 0, &p, sizeof(p), &r, sizeof(r)); |
| if (rv < 0) |
| return rv; |
| |
| printf("Current PWM duty: %d\n", r.duty); |
| return 0; |
| } |
| |
| |
| int cmd_pwm_set_duty(int argc, char *argv[]) |
| { |
| struct ec_params_pwm_set_duty p; |
| char *e; |
| int rv; |
| |
| if (argc != 3) { |
| fprintf(stderr, "Usage: %s <pwm_idx> | kb | disp <duty>\n", |
| argv[0]); |
| return -1; |
| } |
| |
| if (!strcmp(argv[1], "kb")) { |
| p.pwm_type = EC_PWM_TYPE_KB_LIGHT; |
| p.index = 0; |
| } else if (!strcmp(argv[1], "disp")) { |
| p.pwm_type = EC_PWM_TYPE_DISPLAY_LIGHT; |
| p.index = 0; |
| } else { |
| p.pwm_type = EC_PWM_TYPE_GENERIC; |
| p.index = strtol(argv[1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad pwm_idx\n"); |
| return -1; |
| } |
| } |
| |
| p.duty = strtol(argv[2], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad duty.\n"); |
| return -1; |
| } |
| |
| rv = ec_command(EC_CMD_PWM_SET_DUTY, 0, |
| &p, sizeof(p), NULL, 0); |
| if (rv < 0) |
| return rv; |
| |
| printf("PWM set.\n"); |
| return 0; |
| } |
| |
| int cmd_fanduty(int argc, char *argv[]) |
| { |
| struct ec_params_pwm_set_fan_duty_v1 p_v1; |
| char *e; |
| int rv, num_fans; |
| int cmdver = 1; |
| |
| if (!ec_cmd_version_supported(EC_CMD_PWM_SET_FAN_DUTY, cmdver)) { |
| struct ec_params_pwm_set_fan_duty_v0 p_v0; |
| |
| if (argc != 2) { |
| fprintf(stderr, |
| "Usage: %s <percent>\n", argv[0]); |
| return -1; |
| } |
| p_v0.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_v0, sizeof(p_v0), NULL, 0); |
| if (rv < 0) |
| return rv; |
| |
| printf("Fan duty cycle set.\n"); |
| return 0; |
| } |
| |
| if (argc > 3 || (argc == 2 && !strcmp(argv[1], "help")) || argc == 1) { |
| printf("Usage: %s [idx] <percent>\n", argv[0]); |
| printf("'%s 0 50' - Set fan 0 duty cycle to 50 percent\n", |
| argv[0]); |
| printf("'%s 30' - Set all fans duty cycle to 30 percent\n", |
| argv[0]); |
| return -1; |
| } |
| |
| num_fans = get_num_fans(); |
| p_v1.percent = strtol(argv[argc - 1], &e, 0); |
| if (e && *e) { |
| fprintf(stderr, "Bad percent arg.\n"); |
| return -1; |
| } |
| |
| if (argc == 2) { |
| /* Reuse version 0 command if we're setting duty cycle |
| * for all fans */ |
| struct ec_params_pwm_set_fan_duty_v0 p_v0; |
| |
| cmdver = 0; |
| p_v0.percent = p_v1.percent; |
| |
| rv = ec_command(EC_CMD_PWM_SET_FAN_DUTY, cmdver, |
| &p_v0, sizeof(p_v0), NULL, 0); |
| if (rv < 0) |
| return rv; |
| |
| printf("Fan duty cycle set for all fans.\n"); |
| } else { |
| p_v1.fan_idx = strtol(argv[1], &e, 0); |
| if ((e && *e) || (p_v1.fan_idx >= num_fans)) { |
| fprintf(stderr, "Bad fan index.\n"); |
| return -1; |
| } |
| |
| rv = ec_command(EC_CMD_PWM_SET_FAN_DUTY, cmdver, |
| &p_v1, sizeof(p_v1), NULL, 0); |
| if (rv < 0) |
| return rv; |
| |
| printf("Fan %d duty cycle set.\n", p_v1.fan_idx); |
| } |
| |
| 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), |
| LB_SIZES(set_program), |
| LB_SIZES(manual_suspend_ctrl), |
| LB_SIZES(suspend), |
| LB_SIZES(resume), |
| LB_SIZES(get_params_v2_timing), |
| LB_SIZES(set_v2par_timing), |
| LB_SIZES(get_params_v2_tap), |
| LB_SIZES(set_v2par_tap), |
| LB_SIZES(get_params_v2_osc), |
| LB_SIZES(set_v2par_osc), |
| LB_SIZES(get_params_v2_bright), |
| LB_SIZES(set_v2par_bright), |
| LB_SIZES(get_params_v2_thlds), |
| LB_SIZES(set_v2par_thlds), |
| LB_SIZES(get_params_v2_colors), |
| LB_SIZES(set_v2par_colors), |
| }; |
| #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); |
| printf(" %s params2 group [setfile] - get params by group\n" |
| " (or set from file)\n", cmd); |
| printf(" %s program file - load program 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, ¶m, &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_gate_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_gate_delay\n", p->tap_gate_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 lb_rd_timing_v2par_from_file(const char *filename, |
| struct lightbar_params_v2_timing *p) |
| { |
| FILE *fp; |
| char buf[80]; |
| int val[4]; |
| int r = 1; |
| int line = 0; |
| int want, got; |
| |
| 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) |
| |
| 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_gate_delay = val[0]; |
| READ(1); p->tap_display_time = val[0]; |
| #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 int lb_rd_tap_v2par_from_file(const char *filename, |
| struct lightbar_params_v2_tap *p) |
| { |
| FILE *fp; |
| char buf[80]; |
| int val[4]; |
| int r = 1; |
| int line = 0; |
| int want, got; |
| |
| 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) |
| |
| 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
|