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