Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(962)

Unified Diff: src/platform/utils/gpio_setup.py

Issue 2421006: A script to create ACPI based GPIO mapping. (Closed) Base URL: ssh://git@chromiumos-git/chromeos
Patch Set: Addressed review comments. Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/platform/utils/gpio_setup.py
diff --git a/src/platform/utils/gpio_setup.py b/src/platform/utils/gpio_setup.py
new file mode 100755
index 0000000000000000000000000000000000000000..3c71b755bdf5bb587bcc6b0d71fbff90b65faedf
--- /dev/null
+++ b/src/platform/utils/gpio_setup.py
@@ -0,0 +1,230 @@
+#!/usr/bin/python
+
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A script to create symlinks to platform specific GPIO pins.
+
+This script creates a set of symlinks pointing at the sys fs files returning
+the appropriate GPIO pin values. Each symlink is named to represent the actual
+GPIO pin function.
+
+The location of the symlinks generated by this script can be specified using
+the --symlink_root command line option. By default /home/gpio directory is
+used. The symlink directory must exist before this script is run.
+
+The GPIO pins' values are available through a GPIO device present in sys fs.
+The device is identified by its PCI bus address. The default PCI address of
+the GPIO device (set to 0:0:1f.0), can be changed using the --pci_address
+command line option.
+
+The platform specific bit usage of the GPIO device is derived from the ACPI,
+also using files found in a fixed location in sys fs. The default location of
+/sys/bus/platform/devices/chromeos_acpi could be changed using the --acpi_root
+command line option.
+
+Each GPIO pin is represented through ACPI as a subdirectory with several files
+in it. A typical name of the GPIO pin file looks as follows:
+
+<acpi_root>/GPIO.<instance>/GPIO.[0-3]
+
+where <instance> is a zero based number assigned to this GPIO pin by the BIOS.
+
+In particular, file GPIO.0 represents encoded pin signal type (from which the
+symlink name is derived), and file GPIO.2 represents the actual zero based
+GPIO pin number within this GPIO device range.
+
+This script reads the ACPI provided mapping, enables the appropriate GPIO pins
+and creates symlinks mapping these GPIOs' values.
+"""
+
+__author__ = 'The Chromium OS Authors'
+
+import glob
+import os
+import optparse
+import sys
+
+GPIO_ROOT = '/sys/class/gpio'
+GPIO_DEVICE_ROOT = GPIO_ROOT + '/gpiochip'
+GPIO_ENABLE_FILE = '/sys/class/gpio/' + 'export'
+
+# Can be changed using --pci_address command line option.
+GPIO_DEVICE_PCI_ADDRESS = '0000:00:1f.0'
+
+# Can be changed using --acpi_root command line option.
+ACPI_ROOT = '/sys/bus/platform/devices/chromeos_acpi'
+GPIO_SIGNAL_TYPE_EXTENSION = '0'
+GPIO_PIN_NUMBER_EXTENSION = '2'
+
+# can be changed using --symlink_root command line option.
+DEFAULT_SYMLINK_ROOT = '/home/gpio'
+
+# This dictionary maps GPIO signal types codes into their actual names.
+GPIO_SIGNAL_TYPES = {
+ 1: 'recovery_button',
+ 2: 'developer_switch',
+ 3: 'write_protect'
+ }
+
+# Debug header signal type codes are offset by 0x100, the tuple below
+# represents the range of valid codes for the debug header. The range starts
+# at 0x100 and is 0x100 wide.
+GPIO_DEBUG_HEADER_RANGE = (0x100, 0x100)
+
+# This is used to prepare the option parser: each element is a tuple of
+# strings, including the option name and the option default value.
+option_list = (('symlink_root', DEFAULT_SYMLINK_ROOT),
+ ('pci_address', GPIO_DEVICE_PCI_ADDRESS),
+ ('acpi_root', ACPI_ROOT))
+
+# This becomes the option object after the command line is parsed.
+cmd_line_options = None
+
+class GpioSetupError(Exception):
+ pass
+
+
+class GpioChip(object):
+ """Represent GPIO chip available through sys fs.
+
+ Attributes:
+ pci_address: a string, PCI address of this GPIO device
+ base: a number, base global GPIO number of this device (mapped to pin zero
+ in the device range)
+ capacity: a number, shows the number of GPIO pins of this device.
+ description: a multiline string description of this device, initialized
+ after the device is attached. Can be used to dump device
+ information.
+ """
+
+ def __init__(self, pci_address):
+ self.pci_address = pci_address
+ self.base = 0
+ self.capacity = 0
+ self.description = 'not attached'
+
+ def Attach(self):
+ for f in glob.glob(GPIO_DEVICE_ROOT + '*/label'):
+ label = open(f).read().strip()
+ if label == self.pci_address:
+ break
+ else:
+ raise GpioSetupError(
+ 'could not find GPIO PCI device %s' % self.pci_address)
+ directory = os.path.dirname(f)
+ self.base = int(open(directory + '/base').read())
+ self.capacity = int(open(directory + '/ngpio').read())
+ self.description = '\n'.join(['GPIO device at PCI address %s' %
+ self.pci_address,
+ 'Base gpio pin %d' % self.base,
+ 'Capacity %d' % self.capacity])
+
+ def EnablePin(self, pin):
+ """Enable a certain GPIO pin.
+
+ To enable the pin one needs to write its global GPIO number into
+ /sys/class/gpio/export, if this pin has not been enabled yet.
+
+ Inputs:
+ pin: a number, zero based pin number within this device's range.
+ """
+
+ if pin >= self.capacity:
+ raise GpioSetupError('pin %d exceeds capacity of %d' % (
+ pin, self.capacity))
+ global_gpio_number = self.base + pin
+ if not os.path.exists('%s/gpio%d' % (GPIO_ROOT, global_gpio_number)):
+ open(GPIO_ENABLE_FILE, 'w').write('%d' % (global_gpio_number))
+
+ def __str__(self):
+ return self.description
+
+
+def ParseAcpiMappings():
+ """Scan ACPI information about GPIO and generate a mapping.
+
+ Returns: a list of tuples, each tuple consisting of a string representing
+ the GPIO pin name and a number, representing the GPIO pin within
+ the GPIO device space.
+ """
+ acpi_gpio_mapping = []
+ for d in glob.glob('%s/GPIO.[0-9]*' % cmd_line_options.acpi_root):
+ signal_type = int(open('%s/GPIO.%s' % (
+ d, GPIO_SIGNAL_TYPE_EXTENSION)).read())
+
+ pin_number = int(open('%s/GPIO.%s' % (
+ d, GPIO_PIN_NUMBER_EXTENSION)).read())
+
+ if signal_type in GPIO_SIGNAL_TYPES:
+ acpi_gpio_mapping.append((GPIO_SIGNAL_TYPES[signal_type], pin_number))
+ continue
+
+ # This is not a specific signal, could be a debug header pin.
+ debug_header = signal_type - GPIO_DEBUG_HEADER_RANGE[0]
+ if debug_header >= 0 and debug_header < GPIO_DEBUG_HEADER_RANGE[1]:
+ acpi_gpio_mapping.append(('debug_header_%d' % debug_header, pin_number))
+ continue
+
+ # Unrecognized mapping, could happen if BIOS version is ahead of this
+ # script.
+ print 'unknown signal type encoding %d in %d' % (signal_type, d)
+
+ if not acpi_gpio_mapping:
+ raise GpioSetupError('no gpio mapping found. Is ACPI driver installed?')
+
+ return acpi_gpio_mapping
+
+
+def CreateGpioSymlinks(mappings, gpio, symlink_root):
+ if not os.path.exists(symlink_root):
+ raise GpioSetupError('%s does not exist' % symlink_root)
+
+ if not os.path.isdir(symlink_root):
+ raise GpioSetupError('%s is not a directory' % symlink_root)
+
+ if not os.access(symlink_root, os.W_OK):
+ raise GpioSetupError('%s is not writable' % symlink_root)
+
+ try:
+ os.chdir(symlink_root)
+ except OSError:
+ raise GpioSetupError('failed to change directory to %s' % symlink_root)
+
+ for (symlink, pin) in mappings:
+ gpio.EnablePin(pin)
+ source_file = '%s/gpio%d/value' % (GPIO_ROOT, pin + gpio.base)
+ if not os.path.exists(symlink):
+ os.symlink(source_file, symlink)
+ continue
+ if not os.path.islink(symlink):
+ raise GpioSetupError(
+ '%s exists but is not a symlink' % os.path.abspath(symlink))
+ if os.readlink(symlink) != source_file:
+ raise GpioSetupError(
+ '%s points to a wrong file' % os.path.abspath(symlink))
+
+
+def ProcessOptions():
+ global cmd_line_options
+ parser = optparse.OptionParser()
+ for (name, default_value) in option_list:
+ parser.add_option('--' + name, dest=name, default=default_value)
+ (cmd_line_options, _) = parser.parse_args()
+
+
+def main():
+ ProcessOptions()
+ gpioc = GpioChip(cmd_line_options.pci_address)
+ gpioc.Attach()
+ CreateGpioSymlinks(ParseAcpiMappings(), gpioc, cmd_line_options.symlink_root)
+
+
+if __name__ == '__main__':
+ try:
+ main()
+ except GpioSetupError, e:
+ print >> sys.stderr, '%s: %s' % (sys.argv[0].split('/')[-1], e)
+ sys.exit(1)
+ sys.exit(0)
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698