firmware-utiles: add *.attr for GPIO symbolic links
To recognize the polarity of each GPIO, we need to expose the information from
chromeos_acpi interface.
BUG=chrome-os-partner:1940
TEST=(on mario, BIOS ver = G5) gpio_setup; cd /home/gpio; ls -l
# complete output: (output_header[1-7] is stripped)
# debug_header_0 -> /sys/class/gpio/gpio201/value
# debug_header_0.attr -> /sys/bus/platform/devices/chromeos_acpi/GPIO.3/GPIO.1
# developer_switch -> /sys/class/gpio/gpio193/value
# developer_switch.attr -> /sys/bus/platform/devices/chromeos_acpi/GPIO.1/GPIO.1
# recovery_button -> /sys/class/gpio/gpio230/value
# recovery_button.attr -> /sys/bus/platform/devices/chromeos_acpi/GPIO.0/GPIO.1
# write_protect -> /sys/class/gpio/gpio226/value
# write_protect.attr -> /sys/bus/platform/devices/chromeos_acpi/GPIO.2/GPIO.1
for X in *.attr; do echo $X - $(cat $X); done
# debug_header_0.attr - 0
# developer_switch.attr - 1
# recovery_button.attr - 0
# write_protect.attr - 0 (this should be 1 in new BIOS)
Change-Id: Ib42b4662c4369112a8f4fb69989d62f2d1b76590
Review URL: http://codereview.chromium.org/6324005
diff --git a/gpio_setup.cc b/gpio_setup.cc
index 31fa39e..ee72847 100644
--- a/gpio_setup.cc
+++ b/gpio_setup.cc
@@ -69,6 +69,7 @@
#define DEFAULT_SYMLINK_ROOT "/home/gpio"
#define GPIO_SIGNAL_TYPE_EXTENSION "0"
+#define GPIO_ATTRIBUTES_EXTENSION "1"
#define GPIO_PIN_NUMBER_EXTENSION "2"
// Debug header signal type codes are offset by 0x100, the tuple below
@@ -310,7 +311,12 @@
GpioChip() { }
};
-typedef std::pair<string, int> AcpiMappingEntry;
+typedef struct {
+ string name;
+ int index;
+ int pin_number;
+} AcpiMappingEntry;
+
typedef std::vector<AcpiMappingEntry> AcpiMapping;
// Scan ACPI information about GPIO and generate a mapping.
@@ -322,26 +328,32 @@
GlobResult r = glob_glob(format_string("%s/GPIO.[0-9]*", acpi_root.c_str()));
AcpiMapping acpi_gpio_mapping;
GlobResult::iterator i;
+
for (i = r.begin(); i != r.end(); i++) {
+ AcpiMappingEntry entry;
const char *d = i->c_str();
+ const char *dot_index_string = strrchr(d, '.');
int signal_type = atoi(open_read_strip(
format_string("%s/GPIO.%s", d, GPIO_SIGNAL_TYPE_EXTENSION)).c_str());
- int pin_number = atoi(open_read_strip(
+
+ assert(dot_index_string);
+ entry.index = atoi(dot_index_string + 1);
+ entry.pin_number = atoi(open_read_strip(
format_string("%s/GPIO.%s", d, GPIO_PIN_NUMBER_EXTENSION)).c_str());
if (signal_type >= GPIO_SIGNAL_TYPE_MIN &&
signal_type <= static_cast<int>(GPIO_SIGNAL_TYPE_MAX) &&
GPIO_SIGNAL_TYPES[signal_type] != NULL) {
- acpi_gpio_mapping.push_back(AcpiMappingEntry(
- GPIO_SIGNAL_TYPES[signal_type], pin_number));
+ entry.name = GPIO_SIGNAL_TYPES[signal_type];
+ acpi_gpio_mapping.push_back(entry);
continue;
}
// This is not a specific signal, could be a debug header pin.
int debug_header = signal_type - GPIO_DEBUG_HEADER_RANGE[0];
if (debug_header >= 0 && debug_header < GPIO_DEBUG_HEADER_RANGE[1]) {
- acpi_gpio_mapping.push_back(AcpiMappingEntry(
- format_string("debug_header_%d", debug_header), pin_number));
+ entry.name = format_string("debug_header_%d", debug_header);
+ acpi_gpio_mapping.push_back(AcpiMappingEntry(entry));
continue;
}
@@ -356,8 +368,23 @@
return acpi_gpio_mapping;
}
+void CreateSymLink(const string &source_file, const string &symlink) {
+ if (!os_path_exists(symlink)) {
+ os_symlink(source_file.c_str(), symlink.c_str());
+ return;
+ }
+
+ if (!os_path_islink(symlink))
+ GpioSetupError("%s exists but is not a symlink",
+ os_path_abspath(symlink).c_str());
+ if (os_readlink(symlink) != source_file)
+ GpioSetupError("%s points to a wrong file",
+ os_path_abspath(symlink).c_str());
+}
+
void CreateGpioSymlinks(const AcpiMapping& mappings,
GpioChip &gpio,
+ const char *acpi_root,
const char *symlink_root) {
if (!os_path_exists(symlink_root))
GpioSetupError("%s does not exist", symlink_root);
@@ -373,24 +400,20 @@
AcpiMapping::const_iterator i;
for (i = mappings.begin(); i != mappings.end(); ++i) {
- string symlink = i->first;
- int pin = i->second;
- gpio.EnablePin(pin);
+ string symlink, source_file;
+ gpio.EnablePin(i->pin_number);
- string source_file = format_string("%s/gpio%d/value",
- GPIO_ROOT, pin+gpio.base());
- if (!os_path_exists(symlink)) {
- os_symlink(source_file.c_str(), symlink.c_str());
- continue;
- }
+ symlink = i->name;
+ source_file = format_string("%s/gpio%d/value", GPIO_ROOT,
+ i->pin_number + gpio.base());
+ CreateSymLink(source_file, symlink);
- if (!os_path_islink(symlink))
- GpioSetupError("%s exists but is not a symlink",
- os_path_abspath(symlink).c_str());
-
- if (os_readlink(symlink) != source_file)
- GpioSetupError("%s points to a wrong file",
- os_path_abspath(symlink).c_str());
+ symlink = i->name + ".attr";
+ source_file = format_string("%s/GPIO.%d/GPIO.%s",
+ acpi_root,
+ i->index,
+ GPIO_ATTRIBUTES_EXTENSION);
+ CreateSymLink(source_file, symlink);
}
}
@@ -459,6 +482,8 @@
gpioc.Attach();
CreateGpioSymlinks(
ParseAcpiMappings(cmd_line_options.acpi_root),
- gpioc, cmd_line_options.symlink_root.c_str());
+ gpioc,
+ cmd_line_options.acpi_root.c_str(),
+ cmd_line_options.symlink_root.c_str());
return 0;
}