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 sytem."); 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