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