| Index: chromeos_interface.py
 | 
| diff --git a/chromeos_interface.py b/chromeos_interface.py
 | 
| index 0df860969df5b950d49b0a2f61d8237cb262519c..bf96fd15430c75ea1355845cf3074dc674ab3cb2 100755
 | 
| --- a/chromeos_interface.py
 | 
| +++ b/chromeos_interface.py
 | 
| @@ -21,9 +21,117 @@ class ChromeOSInterfaceError(Exception):
 | 
|  class Crossystem(object):
 | 
|      '''A wrapper for the crossystem utility.'''
 | 
|  
 | 
| +    # Code dedicated for user triggering recovery mode through crossystem.
 | 
| +    USER_RECOVERY_REQUEST_CODE = '193'
 | 
| +
 | 
| +    '''
 | 
| +    The first three legacy boot vector digits are the boot vector base (the
 | 
| +    entire vector consists of 5 digits). They used to be reported by the BIOS
 | 
| +    through ACPI, but that scheme has been superseded by the 'crossystem'
 | 
| +    interface.
 | 
| +
 | 
| +    The digits of the boot vector base have the following significance
 | 
| +
 | 
| +    - first digit -
 | 
| +    1 - normal boot
 | 
| +    2 - developer mode boot
 | 
| +    3 - recovery initialed by pressing the recovery button
 | 
| +    4 - recovery from developer mode warning screen
 | 
| +    5 - recovery caused by both firmware images being invalid
 | 
| +    6 - recovery caused by both kernel images being invalid
 | 
| +    8 - recovery initiated by user
 | 
| +
 | 
| +    - second digit -
 | 
| +    0 - recovery firmware
 | 
| +    1 - rewritable firmware A
 | 
| +    2 - rewritable firmware B
 | 
| +
 | 
| +    - third digit -
 | 
| +    0 - Read only (recovery) EC firmware
 | 
| +    1 - rewritable EC firmware
 | 
| +
 | 
| +
 | 
| +    Below is a list of dictionaries to map current system state as reported by
 | 
| +    'crossystem' into the 'legacy' boot vector digits.
 | 
| +
 | 
| +    The three elements of the list represent the three digits of the boot
 | 
| +    vector. Each list element is a dictionary where the key is the legacy boot
 | 
| +    vector value in the appropriate position, and the value is in turn a
 | 
| +    dictionary of name-value pairs.
 | 
| +
 | 
| +    If all name-value pairs of a dictionary element match those reported by
 | 
| +    crossystem, the legacy representation number is considered the appropriate
 | 
| +    vector digit.
 | 
| +
 | 
| +    Note that on some platforms (namely, Mario) same parameters returned by
 | 
| +    crossystem are set to a wrong value. The class init() routine adjust the
 | 
| +    list to support those platforms.
 | 
| +    '''
 | 
| +
 | 
| +    VECTOR_MAPS = [
 | 
| +        { # first vector position
 | 
| +            '1': {
 | 
| +                'devsw_boot': '0',
 | 
| +                'mainfw_type': 'normal',
 | 
| +                'recoverysw_boot': '0',
 | 
| +                },
 | 
| +            '5': {
 | 
| +                'devsw_boot': '0',
 | 
| +                'recoverysw_boot': '0',
 | 
| +                'recovery_reason' : '3',
 | 
| +                'mainfw_type': 'recovery',
 | 
| +                },
 | 
| +            '6': {
 | 
| +                'devsw_boot': '0',
 | 
| +                'recoverysw_boot': '0',
 | 
| +                'recovery_reason' : '66',
 | 
| +                'mainfw_type': 'recovery',
 | 
| +                },
 | 
| +            '8': {
 | 
| +                'devsw_boot': '0',
 | 
| +                'recoverysw_boot': '0',
 | 
| +                'recovery_reason' : USER_RECOVERY_REQUEST_CODE,
 | 
| +                'mainfw_type': 'recovery',
 | 
| +                },
 | 
| +            },
 | 
| +        { # second vector position
 | 
| +            '0': {'mainfw_type': 'recovery',},
 | 
| +            '1': {
 | 
| +                'mainfw_type': 'normal',
 | 
| +                'mainfw_act': 'A'
 | 
| +                },
 | 
| +            '2': {
 | 
| +                'mainfw_type': 'normal',
 | 
| +                'mainfw_act': 'B'
 | 
| +                },
 | 
| +            },
 | 
| +        { # third vector position
 | 
| +            '0': {'ecfw_act': 'RO',},
 | 
| +            '1': {'ecfw_act': 'RW',},
 | 
| +            },
 | 
| +        ]
 | 
| +
 | 
|      def init(self, cros_if):
 | 
| +        '''Init the instance. If running on Mario - adjust the map.'''
 | 
| +
 | 
|          self.cros_if = cros_if
 | 
|  
 | 
| +        # Hack Alert!!! Adjust vector map to work on Mario
 | 
| +        fwid = self.__getattr__('fwid').lower()
 | 
| +        if not 'mario' in fwid:
 | 
| +            return
 | 
| +        # Mario firmware is broken and always reports recovery switch as set
 | 
| +        # at boot time when booting up in recovery mode. This is why we
 | 
| +        # exclude recoverysw_boot from the map when running on mario.
 | 
| +        for state in self.VECTOR_MAPS[0].itervalues():
 | 
| +            if state['mainfw_type'] != 'recovery':
 | 
| +                continue
 | 
| +            if 'recoverysw_boot' in state:
 | 
| +                del(state['recoverysw_boot'])
 | 
| +            if state['recovery_reason'] == self.USER_RECOVERY_REQUEST_CODE:
 | 
| +                # This is the only recovery reason Mario knows about
 | 
| +                state['recovery_reason'] = '1'
 | 
| +
 | 
|      def __getattr__(self, name):
 | 
|          '''
 | 
|          Retrieve a crosssystem attribute.
 | 
| @@ -40,84 +148,27 @@ class Crossystem(object):
 | 
|          else:
 | 
|              self.cros_if.run_shell_command('crossystem "%s=%s"' % (name, value))
 | 
|  
 | 
| +    def request_recovery(self):
 | 
| +        '''Request recovery mode next time the target reboots.'''
 | 
|  
 | 
| -    def get_boot_vector_base(self):
 | 
| -        '''
 | 
| -        Convert system state into a legacy boot vector base.
 | 
| -
 | 
| -        The first three legacy boot vector digits are the boot vector base
 | 
| -        (the entire vector consists of 5 digits). They used to be reported by
 | 
| -        the BIOS through ACPI, but that scheme has been superseded by the
 | 
| -        'crossystem' interface.
 | 
| +        self.__setattr__('recovery_request', self.USER_RECOVERY_REQUEST_CODE)
 | 
|  
 | 
| -        The digits of the boot vector base have the following significance
 | 
| -
 | 
| -        - first digit -
 | 
| -        1 - normal boot
 | 
| -        2 - developer mode boot
 | 
| -        3 - recovery initialed by pressing the recovery button
 | 
| -        4 - recovery from developer mode warning screen
 | 
| -        5 - recovery caused by both firmware images being invalid
 | 
| -        6 - recovery caused by both kernel images being invalid
 | 
| -
 | 
| -        - second digit -
 | 
| -        0 - recovery firmware
 | 
| -        1 - rewritable firmware A
 | 
| -        2 - rewritable firmware B
 | 
| -
 | 
| -        - third digit -
 | 
| -        0 - Read only (recovery) EC firmware
 | 
| -        1 - rewritable EC firmware
 | 
| -
 | 
| -
 | 
| -        This function uses a three tuple of dictionaries to map current system
 | 
| -        state as reported by 'crossystem' into the 'legacy' boot vector
 | 
| -        digits.
 | 
| -
 | 
| -        Each tuple element is a dictionary, where the key is the 'legacy'
 | 
| -        representation of the state, and the value is a yet another dictionary
 | 
| -        of name-value pairs.
 | 
| -
 | 
| -        If all name-value pairs match those in the crossystem output, the
 | 
| -        legacy representation number is returned as the appropriate vector
 | 
| -        number.
 | 
| +    def get_boot_vector_base(self):
 | 
| +        '''Convert system state into a legacy boot vector base.
 | 
|  
 | 
| -        The function returns a list of three digits in symbolic representation.
 | 
| +        The function looks up the VECTOR_MAPS list above to find the digits
 | 
| +        matching the current crossystem output, and returns a list of three
 | 
| +        digits in symbolic representation, which become the base of the 5
 | 
| +        digit boot state vector.
 | 
|  
 | 
| -        Should it be impossible to interpret the state, the function returns a
 | 
| -        partially built list, which is an indication of a problem for the
 | 
| +        Should it be impossible to interpret the state, the function returns
 | 
| +        a partially built list, which is an indication of a problem for the
 | 
|          caller (list shorter than 3 elements).
 | 
|          '''
 | 
|  
 | 
| -        vector_maps = (
 | 
| -            { # first vector position
 | 
| -                '1': {
 | 
| -                    'devsw_boot': '0',
 | 
| -                    'recoverysw_boot': '0',
 | 
| -                    'recovery_reason' : '0',
 | 
| -                    'tried_fwb' : '0',
 | 
| -                    },
 | 
| -                },
 | 
| -            { # second vector position
 | 
| -                '0': {'mainfw_type': 'recovery',},
 | 
| -                '1': {
 | 
| -                    'mainfw_type': 'normal',
 | 
| -                    'mainfw_act': 'A'
 | 
| -                    },
 | 
| -                '2': {
 | 
| -                    'mainfw_type': 'normal',
 | 
| -                    'mainfw_act': 'B'
 | 
| -                    },
 | 
| -                },
 | 
| -            { # third vector position
 | 
| -                '0': {'ecfw_act': 'RO',},
 | 
| -                '1': {'ecfw_act': 'RW',},
 | 
| -                },
 | 
| -        )
 | 
| -
 | 
|          boot_vector = []
 | 
|  
 | 
| -        for vector_map in vector_maps:
 | 
| +        for vector_map in self.VECTOR_MAPS:
 | 
|              for (digit, values) in vector_map.iteritems():
 | 
|                  for (name, value) in values.iteritems():
 | 
|                      if self.__getattr__(name) != value:
 | 
| @@ -129,7 +180,8 @@ class Crossystem(object):
 | 
|          return boot_vector
 | 
|  
 | 
|      def dump(self):
 | 
| -        '''Dump all values as multiline text.'''
 | 
| +        '''Dump all crossystem values as multiline text.'''
 | 
| +
 | 
|          return '\n'.join(self.cros_if.run_shell_command_get_output(
 | 
|              'crossystem'))
 | 
|  
 | 
| 
 |