1
2
3
4
5
6
7
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
26
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
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