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;
 }