aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power
diff options
context:
space:
mode:
authorThomas Renninger <trenn@suse.de>2014-04-07 09:16:57 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-04-28 06:36:56 -0400
commitd7cddbb07b18cc45e57420005850ca0326b9e074 (patch)
tree7d640a12341524d0227c7829e5ec990dd378ad13 /tools/power
parentd1db0eea852497762cab43b905b879dfcd3b8987 (diff)
ACPI / tools: Introduce ec_access.c - tool to access the EC
This userspace tool accesses the EC through the ec_sys debug driver (through /sys/kernel/debug/ec/ec0/io). The EC command/data registers cannot be accessed directly, because they may be manipulated by the AML interpreter in parallel. The ec_sys driver synchronizes user space (debug) access with the AML interpreter. Signed-off-by: Thomas Renninger <trenn@suse.de> [rjw: Changelog] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'tools/power')
-rw-r--r--tools/power/acpi/Makefile2
-rw-r--r--tools/power/acpi/tools/ec/Makefile22
-rw-r--r--tools/power/acpi/tools/ec/ec_access.c238
3 files changed, 262 insertions, 0 deletions
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index c2c0f20067a5..c225d6d9fb29 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -19,6 +19,8 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
19$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 19$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
20endif 20endif
21 21
22SUBDIRS = tools/ec
23
22# --- CONFIGURATION BEGIN --- 24# --- CONFIGURATION BEGIN ---
23 25
24# Set the following to `true' to make a unstripped, unoptimized 26# Set the following to `true' to make a unstripped, unoptimized
diff --git a/tools/power/acpi/tools/ec/Makefile b/tools/power/acpi/tools/ec/Makefile
new file mode 100644
index 000000000000..b7b0b929bd32
--- /dev/null
+++ b/tools/power/acpi/tools/ec/Makefile
@@ -0,0 +1,22 @@
1ec_access: ec_access.o
2 $(ECHO) " LD " $@
3 $(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $< -o $@
4 $(QUIET) $(STRIPCMD) $@
5
6%.o: %.c
7 $(ECHO) " CC " $@
8 $(QUIET) $(CC) -c $(CFLAGS) -o $@ $<
9
10all: ec_access
11
12install:
13 $(INSTALL) -d $(DESTDIR)${sbindir}
14 $(INSTALL_PROGRAM) ec_access $(DESTDIR)${sbindir}
15
16uninstall:
17 - rm -f $(DESTDIR)${sbindir}/ec_access
18
19clean:
20 -rm -f $(OUTPUT)ec_access
21
22.PHONY: all install uninstall
diff --git a/tools/power/acpi/tools/ec/ec_access.c b/tools/power/acpi/tools/ec/ec_access.c
new file mode 100644
index 000000000000..6b8aaed44f2c
--- /dev/null
+++ b/tools/power/acpi/tools/ec/ec_access.c
@@ -0,0 +1,238 @@
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}