blob: 277749b9bf2a91f22ea0509f46c7dee83d95bc54 [file] [log] [blame]
Randall Spangler54218662011-02-07 11:20:20 -08001/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6#include <stdio.h>
7#include <string.h>
8
9#include "host_common.h"
10
11#include "crossystem.h"
12#include "utility.h"
13#include "vboot_common.h"
14
15/* ACPI constants from Chrome OS Main Processor Firmware Spec */
16/* GPIO signal types */
17#define GPIO_SIGNAL_TYPE_RECOVERY 1
18#define GPIO_SIGNAL_TYPE_DEV 2
19#define GPIO_SIGNAL_TYPE_WP 3
20/* CHSW bitflags */
21#define CHSW_RECOVERY_BOOT 0x00000002
22#define CHSW_RECOVERY_EC_BOOT 0x00000004
23#define CHSW_DEV_BOOT 0x00000020
24#define CHSW_WP_BOOT 0x00000200
25
26/* Base name for ACPI files */
27#define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi"
28/* Paths for frequently used ACPI files */
29#define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV"
30#define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW"
31#define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO"
32
33/* Base name for GPIO files */
34#define GPIO_BASE_PATH "/sys/class/gpio"
35#define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
36
37/* Read a string from a file. Passed the destination, dest size, and
38 * filename to read.
39 *
40 * Returns the destination, or NULL if error. */
41char* ReadFileString(char* dest, int size, const char* filename) {
42 char* got;
43 FILE* f;
44
45 f = fopen(filename, "rt");
46 if (!f)
47 return NULL;
48
49 got = fgets(dest, size, f);
50 fclose(f);
51 return got;
52}
53
54
55/* Read an integer from a file.
56 *
57 * Returns the parsed integer, or -1 if error. */
58int ReadFileInt(const char* filename) {
59 char buf[64];
60 int value;
61 char* e = NULL;
62
63 if (!ReadFileString(buf, sizeof(buf), filename))
64 return -1;
65
66 /* Convert to integer. Allow characters after the int ("123 blah"). */
67 value = strtol(buf, &e, 0);
68 if (e == buf)
69 return -1; /* No characters consumed, so conversion failed */
70
71 return value;
72}
73
74
75/* Check if a bit is set in a file which contains an integer.
76 *
77 * Returns 1 if the bit is set, 0 if clear, or -1 if error. */
78int ReadFileBit(const char* filename, int bitmask) {
79 int value = ReadFileInt(filename);
80 if (value == -1)
81 return -1;
82 else return (value & bitmask ? 1 : 0);
83}
84
85
Randall Spanglerc80fe652011-02-17 11:06:47 -080086/* Return true if the FWID starts with the specified string. */
87static int FwidStartsWith(const char *start) {
88 char fwid[128];
89 if (!VbGetSystemPropertyString("fwid", fwid, sizeof(fwid)))
90 return 0;
91
92 return 0 == strncmp(fwid, start, strlen(start));
93}
94
95
Randall Spangler54218662011-02-07 11:20:20 -080096/* Read a GPIO of the specified signal type (see ACPI GPIO SignalType).
97 *
98 * Returns 1 if the signal is asserted, 0 if not asserted, or -1 if error. */
99int ReadGpio(int signal_type) {
100 char name[128];
101 int index = 0;
102 int gpio_type;
103 int active_high;
104 int controller_offset;
105 char controller_name[128];
106 int value;
107
108 /* Scan GPIO.* to find a matching signal type */
109 for (index = 0; ; index++) {
110 snprintf(name, sizeof(name), "%s.%d/GPIO.0", ACPI_GPIO_PATH, index);
111 gpio_type = ReadFileInt(name);
112 if (gpio_type == signal_type)
113 break;
114 else if (gpio_type == -1)
115 return -1; /* Ran out of GPIOs before finding a match */
116 }
117
118 /* Read attributes and controller info for the GPIO */
119 snprintf(name, sizeof(name), "%s.%d/GPIO.1", ACPI_GPIO_PATH, index);
120 active_high = ReadFileBit(name, 0x00000001);
121 snprintf(name, sizeof(name), "%s.%d/GPIO.2", ACPI_GPIO_PATH, index);
122 controller_offset = ReadFileInt(name);
123 if (active_high == -1 || controller_offset == -1)
124 return -1; /* Missing needed info */
125
126 /* We only support the NM10 for now */
127 snprintf(name, sizeof(name), "%s.%d/GPIO.3", ACPI_GPIO_PATH, index);
128 if (!ReadFileString(controller_name, sizeof(controller_name), name))
129 return -1;
130 if (0 != strcmp(controller_name, "NM10"))
131 return -1;
132
133 /* Assume the NM10 has offset 192 */
134 /* TODO: should really check gpiochipNNN/label to see if it's the
135 * address we expect for the NM10, and then read the offset from
136 * gpiochipNNN/base. */
137 controller_offset += 192;
138
139 /* Try reading the GPIO value */
140 snprintf(name, sizeof(name), "%s/gpio%d/value",
141 GPIO_BASE_PATH, controller_offset);
142 value = ReadFileInt(name);
143
144 if (value == -1) {
145 /* Try exporting the GPIO */
146 FILE* f = fopen(GPIO_EXPORT_PATH, "wt");
147 if (!f)
148 return -1;
149 fprintf(f, "%d", controller_offset);
150 fclose(f);
151
152 /* Try re-reading the GPIO value */
153 value = ReadFileInt(name);
154 }
155
156 if (value == -1)
157 return -1;
158
159 /* Compare the GPIO value with the active value and return 1 if match. */
160 return (value == active_high ? 1 : 0);
161}
162
163
164/* Read a system property integer.
165 *
166 * Returns the property value, or -1 if error. */
167int VbGetSystemPropertyInt(const char* name) {
Randall Spanglerc80fe652011-02-17 11:06:47 -0800168 int value = -1;
Randall Spangler54218662011-02-07 11:20:20 -0800169
170 if (!strcasecmp(name,"devsw_cur")) {
Randall Spanglerc80fe652011-02-17 11:06:47 -0800171 value = ReadGpio(GPIO_SIGNAL_TYPE_DEV);
Randall Spangler54218662011-02-07 11:20:20 -0800172 } else if (!strcasecmp(name,"devsw_boot")) {
Randall Spanglerc80fe652011-02-17 11:06:47 -0800173 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT);
Randall Spangler54218662011-02-07 11:20:20 -0800174 } else if (!strcasecmp(name,"recoverysw_cur")) {
Randall Spanglerc80fe652011-02-17 11:06:47 -0800175 value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY);
Randall Spangler54218662011-02-07 11:20:20 -0800176 } else if (!strcasecmp(name,"recoverysw_boot")) {
Randall Spanglerc80fe652011-02-17 11:06:47 -0800177 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT);
Randall Spangler54218662011-02-07 11:20:20 -0800178 } else if (!strcasecmp(name,"recoverysw_ec_boot")) {
Randall Spanglerc80fe652011-02-17 11:06:47 -0800179 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT);
Randall Spangler54218662011-02-07 11:20:20 -0800180 } else if (!strcasecmp(name,"wpsw_cur")) {
Randall Spanglerc80fe652011-02-17 11:06:47 -0800181 value = ReadGpio(GPIO_SIGNAL_TYPE_WP);
182 if (-1 != value && FwidStartsWith("Mario."))
183 value = 1 - value; /* Mario reports this backwards */
Randall Spangler54218662011-02-07 11:20:20 -0800184 } else if (!strcasecmp(name,"wpsw_boot")) {
Randall Spanglerc80fe652011-02-17 11:06:47 -0800185 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT);
186 if (-1 != value && FwidStartsWith("Mario."))
187 value = 1 - value; /* Mario reports this backwards */
188 }
Randall Spangler54218662011-02-07 11:20:20 -0800189
190 /* TODO: remaining properties from spec */
Randall Spanglerc80fe652011-02-17 11:06:47 -0800191
192 return value;
Randall Spangler54218662011-02-07 11:20:20 -0800193}
194
195
196/* Read a system property string into a destination buffer of the specified
197 * size.
198 *
199 * Returns the passed buffer, or NULL if error. */
200const char* VbGetSystemPropertyString(const char* name, char* dest, int size) {
201
202 if (!strcasecmp(name,"hwid")) {
203 return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID");
204 } else if (!strcasecmp(name,"fwid")) {
205 return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID");
206 } else if (!strcasecmp(name,"ro_fwid")) {
207 return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID");
208 } else
209 return NULL;
210
211 /* TODO: remaining properties from spec */
212}
213
214
215/* Set a system property integer.
216 *
217 * Returns 0 if success, -1 if error. */
218int VbSetSystemPropertyInt(const char* name, int value) {
219
220 /* TODO: support setting */
221 return -1;
222}
223
224
225/* Set a system property string.
226 *
227 * Returns 0 if success, -1 if error. */
228int VbSetSystemPropertyString(const char* name, const char* value) {
229
230 /* TODO: support setting */
231 return -1;
232}