| 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)
|
|
|