• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 static int read_mode = -1;
31 static int sleep_time;
32 static int write_byte_offset = -1;
33 static int read_byte_offset = -1;
34 static uint8_t write_value = -1;
35 
usage(char progname[],int exit_status)36 void 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 
parse_opts(int argc,char * argv[])54 void 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 
dump_ec(int fd)126 void 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 
read_ec_val(int fd,int byte_offset)176 void 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 
write_ec_val(int fd,int byte_offset,uint8_t value)193 void 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 
main(int argc,char * argv[])207 int 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