linux/tools/power/acpi/tools/ec/ec_access.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * ec_access.c
   4 *
   5 * Copyright (C) 2010 SUSE Linux Products GmbH
   6 * Author:
   7 *      Thomas Renninger <trenn@suse.de>
   8 */
   9
  10#include <fcntl.h>
  11#include <err.h>
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <libgen.h>
  15#include <unistd.h>
  16#include <getopt.h>
  17#include <stdint.h>
  18#include <sys/types.h>
  19#include <sys/stat.h>
  20
  21
  22#define EC_SPACE_SIZE 256
  23#define SYSFS_PATH "/sys/kernel/debug/ec/ec0/io"
  24
  25/* TBD/Enhancements:
  26   - Provide param for accessing different ECs (not supported by kernel yet)
  27*/
  28
  29static int read_mode = -1;
  30static int sleep_time;
  31static int write_byte_offset = -1;
  32static int read_byte_offset = -1;
  33static uint8_t write_value = -1;
  34
  35void usage(char progname[], int exit_status)
  36{
  37        printf("Usage:\n");
  38        printf("1) %s -r [-s sleep]\n", basename(progname));
  39        printf("2) %s -b byte_offset\n", basename(progname));
  40        printf("3) %s -w byte_offset -v value\n\n", basename(progname));
  41
  42        puts("\t-r [-s sleep]      : Dump EC registers");
  43        puts("\t                     If sleep is given, sleep x seconds,");
  44        puts("\t                     re-read EC registers and show changes");
  45        puts("\t-b offset          : Read value at byte_offset (in hex)");
  46        puts("\t-w offset -v value : Write value at byte_offset");
  47        puts("\t-h                 : Print this help\n\n");
  48        puts("Offsets and values are in hexadecimal number system.");
  49        puts("The offset and value must be between 0 and 0xff.");
  50        exit(exit_status);
  51}
  52
  53void parse_opts(int argc, char *argv[])
  54{
  55        int c;
  56
  57        while ((c = getopt(argc, argv, "rs:b:w:v:h")) != -1) {
  58
  59                switch (c) {
  60                case 'r':
  61                        if (read_mode != -1)
  62                                usage(argv[0], EXIT_FAILURE);
  63                        read_mode = 1;
  64                        break;
  65                case 's':
  66                        if (read_mode != -1 && read_mode != 1)
  67                                usage(argv[0], EXIT_FAILURE);
  68
  69                        sleep_time = atoi(optarg);
  70                        if (sleep_time <= 0) {
  71                                sleep_time = 0;
  72                                usage(argv[0], EXIT_FAILURE);
  73                                printf("Bad sleep time: %s\n", optarg);
  74                        }
  75                        break;
  76                case 'b':
  77                        if (read_mode != -1)
  78                                usage(argv[0], EXIT_FAILURE);
  79                        read_mode = 1;
  80                        read_byte_offset = strtoul(optarg, NULL, 16);
  81                        break;
  82                case 'w':
  83                        if (read_mode != -1)
  84                                usage(argv[0], EXIT_FAILURE);
  85                        read_mode = 0;
  86                        write_byte_offset = strtoul(optarg, NULL, 16);
  87                        break;
  88                case 'v':
  89                        write_value = strtoul(optarg, NULL, 16);
  90                        break;
  91                case 'h':
  92                        usage(argv[0], EXIT_SUCCESS);
  93                default:
  94                        fprintf(stderr, "Unknown option!\n");
  95                        usage(argv[0], EXIT_FAILURE);
  96                }
  97        }
  98        if (read_mode == 0) {
  99                if (write_byte_offset < 0 ||
 100                    write_byte_offset >= EC_SPACE_SIZE) {
 101                        fprintf(stderr, "Wrong byte offset 0x%.2x, valid: "
 102                                "[0-0x%.2x]\n",
 103                                write_byte_offset, EC_SPACE_SIZE - 1);
 104                        usage(argv[0], EXIT_FAILURE);
 105                }
 106                if (write_value < 0 ||
 107                    write_value >= 255) {
 108                        fprintf(stderr, "Wrong byte offset 0x%.2x, valid:"
 109                                "[0-0xff]\n", write_byte_offset);
 110                        usage(argv[0], EXIT_FAILURE);
 111                }
 112        }
 113        if (read_mode == 1 && read_byte_offset != -1) {
 114                if (read_byte_offset < -1 ||
 115                    read_byte_offset >= EC_SPACE_SIZE) {
 116                        fprintf(stderr, "Wrong byte offset 0x%.2x, valid: "
 117                                "[0-0x%.2x]\n",
 118                                read_byte_offset, EC_SPACE_SIZE - 1);
 119                        usage(argv[0], EXIT_FAILURE);
 120                }
 121        }
 122        /* Add additional parameter checks here */
 123}
 124
 125void dump_ec(int fd)
 126{
 127        char buf[EC_SPACE_SIZE];
 128        char buf2[EC_SPACE_SIZE];
 129        int byte_off, bytes_read;
 130
 131        bytes_read = read(fd, buf, EC_SPACE_SIZE);
 132
 133        if (bytes_read == -1)
 134                err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH);
 135
 136        if (bytes_read != EC_SPACE_SIZE)
 137                fprintf(stderr, "Could only read %d bytes\n", bytes_read);
 138
 139        printf("     00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F");
 140        for (byte_off = 0; byte_off < bytes_read; byte_off++) {
 141                if ((byte_off % 16) == 0)
 142                        printf("\n%.2X: ", byte_off);
 143                printf(" %.2x ", (uint8_t)buf[byte_off]);
 144        }
 145        printf("\n");
 146
 147        if (!sleep_time)
 148                return;
 149
 150        printf("\n");
 151        lseek(fd, 0, SEEK_SET);
 152        sleep(sleep_time);
 153
 154        bytes_read = read(fd, buf2, EC_SPACE_SIZE);
 155
 156        if (bytes_read == -1)
 157                err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH);
 158
 159        if (bytes_read != EC_SPACE_SIZE)
 160                fprintf(stderr, "Could only read %d bytes\n", bytes_read);
 161
 162        printf("     00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F");
 163        for (byte_off = 0; byte_off < bytes_read; byte_off++) {
 164                if ((byte_off % 16) == 0)
 165                        printf("\n%.2X: ", byte_off);
 166
 167                if (buf[byte_off] == buf2[byte_off])
 168                        printf(" %.2x ", (uint8_t)buf2[byte_off]);
 169                else
 170                        printf("*%.2x ", (uint8_t)buf2[byte_off]);
 171        }
 172        printf("\n");
 173}
 174
 175void read_ec_val(int fd, int byte_offset)
 176{
 177        uint8_t buf;
 178        int error;
 179
 180        error = lseek(fd, byte_offset, SEEK_SET);
 181        if (error != byte_offset)
 182                err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset);
 183
 184        error = read(fd, &buf, 1);
 185        if (error != 1)
 186                err(EXIT_FAILURE, "Could not read byte 0x%.2x from %s\n",
 187                    byte_offset, SYSFS_PATH);
 188        printf("0x%.2x\n", buf);
 189        return;
 190}
 191
 192void write_ec_val(int fd, int byte_offset, uint8_t value)
 193{
 194        int error;
 195
 196        error = lseek(fd, byte_offset, SEEK_SET);
 197        if (error != byte_offset)
 198                err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset);
 199
 200        error = write(fd, &value, 1);
 201        if (error != 1)
 202                err(EXIT_FAILURE, "Cannot write value 0x%.2x to offset 0x%.2x",
 203                    value, byte_offset);
 204}
 205
 206int main(int argc, char *argv[])
 207{
 208        int file_mode = O_RDONLY;
 209        int fd;
 210
 211        parse_opts(argc, argv);
 212
 213        if (read_mode == 0)
 214                file_mode = O_WRONLY;
 215        else if (read_mode == 1)
 216                file_mode = O_RDONLY;
 217        else
 218                usage(argv[0], EXIT_FAILURE);
 219
 220        fd = open(SYSFS_PATH, file_mode);
 221        if (fd == -1)
 222                err(EXIT_FAILURE, "%s", SYSFS_PATH);
 223
 224        if (read_mode)
 225                if (read_byte_offset == -1)
 226                        dump_ec(fd);
 227                else if (read_byte_offset < 0 ||
 228                         read_byte_offset >= EC_SPACE_SIZE)
 229                        usage(argv[0], EXIT_FAILURE);
 230                else
 231                        read_ec_val(fd, read_byte_offset);
 232        else
 233                write_ec_val(fd, write_byte_offset, write_value);
 234        close(fd);
 235
 236        exit(EXIT_SUCCESS);
 237}
 238