Chromium Code Reviews| Index: gft_hwcomp.py |
| diff --git a/gft_hwcomp.py b/gft_hwcomp.py |
| index e83a80c21fa9414938c51fb547397f8e4b4eb25e..03905d97dff5a5c8df1c74d96b03ac98f6ab23ae 100755 |
| --- a/gft_hwcomp.py |
| +++ b/gft_hwcomp.py |
| @@ -5,6 +5,7 @@ |
| # found in the LICENSE file. |
| import glob |
| +import imp |
| import os |
| import pprint |
| import re |
| @@ -19,10 +20,6 @@ import vblock |
| from gft_common import DebugMsg, VerboseMsg, WarningMsg, ErrorMsg, ErrorDie |
| -def Memorize(f): |
| - return gft_common.ThreadSafe(gft_common.Memorize(f)) |
| - |
| - |
| class HardwareComponents(object): |
| """ Hardware Components Scanner """ |
| @@ -93,6 +90,13 @@ class HardwareComponents(object): |
| _not_present = '' |
| _no_match = 'No match' |
| + # Type id for connection management (compatible to flimflam) |
| + _type_3g = 'cellular' |
| + _type_ethernet = 'ethernet' |
| + _type_wireless = 'wifi' |
| + |
| + _flimflam_dir = '/usr/local/lib/flimflam/test' |
| + |
| def __init__(self, verbose=False): |
| self._initialized = False |
| self._verbose = verbose |
| @@ -122,6 +126,10 @@ class HardwareComponents(object): |
| # -------------------------------------------------------------------- |
| # System Probing Utilities |
| + def Memorize(f): |
| + """ Decorator for thread-safe memorization """ |
| + return gft_common.ThreadSafe(gft_common.Memorize(f)) |
| + |
| @Memorize |
| def load_module(self, name): |
| grep_cmd = ('lsmod 2>/dev/null | grep -q %s' % name) |
| @@ -166,21 +174,70 @@ class HardwareComponents(object): |
| return device_list |
| @Memorize |
| + def import_flimflam_module(self): |
| + """ Tries to load flimflam module from current system """ |
| + if not os.path.exists(self._flimflam_dir): |
| + DebugMsg('no flimflam installed in %s' % self._flimflam_dir) |
| + return None |
| + try: |
| + return imp.load_module('flimflam', |
| + *imp.find_module('flimflam', [self._flimflam_dir])) |
| + except ImportError: |
| + ErrorMsg('Failed to import flimflam.') |
| + except: |
| + ErrorMsg('Failed to load flimflam.') |
| + return None |
| + |
| + @Memorize |
| + def load_flimflam(self): |
| + """Gets information provided by flimflam (connection manager) |
| + |
| + Returns |
| + (None, None) if failed to load module, otherwise |
| + (connection_path, connection_info) where |
| + connection_path is a dict in {type: device_path}, |
| + connection_info is a dict of {type: {attribute: value}}. |
| + """ |
| + flimflam = self.import_flimflam_module() |
| + if not flimflam: |
| + return (None, None) |
| + path = {} |
| + info = {} |
| + info_attribute_names = { |
| + self._type_3g: ['Carrier', 'FirmwareRevision', 'HardwareRevision', |
| + 'ModelID', 'Manufacturer'], |
| + } |
| + devices = flimflam.FlimFlam().GetObjectList('Device') |
| + unpack = flimflam.convert_dbus_value |
| + # TODO(hungte) support multiple devices existence in future |
| + for device in devices: |
| + # populate the 'path' collection |
| + prop = device.GetProperties() |
| + prop_type = unpack(prop['Type']) |
| + path[prop_type] = '/sys/class/net/%s/device' % unpack(prop['Interface']) |
| + if prop_type not in info_attribute_names: |
| + continue |
| + # populate the 'info' collection |
| + info[prop_type] = dict(( |
| + (key, unpack(prop['Cellular.%s' % key])) |
| + for key in info_attribute_names[prop_type] |
| + if ('Cellular.%s' % key) in prop)) |
| + return (path, info) |
| + |
| + @Memorize |
| def _get_all_connection_info(self): |
| """ Probes available connectivity and device information """ |
| connection_info = { |
| - 'wireless': '/sys/class/net/wlan0/device', |
| - 'ethernet': '/sys/class/net/eth0/device', |
| - '3g': '/sys/class/tty/ttyUSB0/device', |
| + self._type_wireless: '/sys/class/net/wlan0/device', |
| + self._type_ethernet: '/sys/class/net/eth0/device', |
| + # 3g(cellular) may also be /sys/class/net/usb0 |
| + self._type_3g: '/sys/class/tty/ttyUSB0/device', |
| } |
| - flimflam_scripts_base = '/usr/local/lib/flimflam/test' |
| - if os.path.exists(flimflam_scripts_base): |
| - # TODO(hungte) use flimflam to update the device list. |
| - # Currently flimflam seem to be not very stable, so let's ignore it. |
| - list_modems = os.path.join(flimflam_scripts_base, 'mm-list-modems') |
| - part_id = gft_common.SystemOutput(list_modems, ignore_status=True).strip() |
| - if part_id: |
| - DebugMsg('mm-list-modems reported: %s' % part_id) |
| + (path, _) = self.load_flimflam() |
| + if path is not None: |
| + # trust flimflam instead. |
| + for k in connection_info: |
| + connection_info[k] = (path[k] if k in path else '') |
| return connection_info |
| def _get_sysfs_device_info(self, path, primary, optional=[]): |
| @@ -245,6 +302,8 @@ class HardwareComponents(object): |
| Returns |
| An identifier string, or self._not_present if not available. |
| """ |
| + if not path: |
| + return self._not_present |
| path = os.path.realpath(path) |
| if not os.path.isdir(path): |
| return self._not_present |
| @@ -356,7 +415,7 @@ class HardwareComponents(object): |
| return gft_fwhash.GetBIOSReadOnlyHash(file_source=image_file) |
| def get_part_id_3g(self): |
| - device_path = self._get_all_connection_info()['3g'] |
| + device_path = self._get_all_connection_info()[self._type_3g] |
| return self.get_sysfs_device_id(device_path) or self._not_present |
| def get_part_id_audio_codec(self): |
| @@ -436,7 +495,7 @@ class HardwareComponents(object): |
| return part_id |
| def get_part_id_ethernet(self): |
| - device_path = self._get_all_connection_info()['ethernet'] |
| + device_path = self._get_all_connection_info()[self._type_ethernet] |
| return self.get_sysfs_device_id(device_path) or self._not_present |
| def get_part_id_flash_chip(self): |
| @@ -492,7 +551,7 @@ class HardwareComponents(object): |
| return self.get_sysfs_device_id('/sys/class/video4linux/video0/device') |
| def get_part_id_wireless(self): |
| - device_path = self._get_all_connection_info()['wireless'] |
| + device_path = self._get_all_connection_info()[self._type_wireless] |
| return self.get_sysfs_device_id(device_path) or self._not_present |
| def get_vendor_id_touchpad_synaptics(self): |
| @@ -539,34 +598,22 @@ class HardwareComponents(object): |
| return part_id |
| def get_version_3g_firmware(self): |
| - version = 'Unknown' |
| - # TODO(hungte) use mm.py directly to prevent the need of shell scripting |
| - modem_status = gft_common.SystemOutput('modem status', |
| - ignore_status=True).splitlines() |
| - if not modem_status: |
| - return self._not_present |
| - |
| - # status format: |
| - # Manufacturer: $VENDOR |
| - # Modem: $MODEM |
| - # Version: $VERSION_MAY_BE_MULTILINE |
| - def ParseInfo(name): |
| - data = [line for line in modem_status if line.find('%s: ' % name) >= 0] |
| - assert len(data) < 2 |
| - return data[0].split(': ', 1)[1].strip() |
| - |
| - version = ParseInfo('Version') |
| - vendor = ParseInfo('Manufacturer') |
| - modem = ParseInfo('Modem') |
| - |
| - if vendor == 'Samsung' and modem == 'GT-Y3300X': |
| - # The real version is in "Version:" +2 lines |
| - version = '' |
| - for i, line in enumerate(modem_status): |
| - if 'Version: ' in line: |
| - version = modem_status[i + 2].strip() |
| - break |
| - return version or 'Unknown' |
| + (_, attributes) = self.load_flimflam() |
|
Jason Glasgow
2011/04/15 22:39:44
Looks okay to me. I would have used mm.py and gon
|
| + if attributes and (self._type_3g in attributes): |
| + # A list of possible version info combination, since the supported fields |
| + # may differ for partners. |
| + version_formats = [ |
| + ['Carrier', 'FirmwareRevision'], |
| + ['FirmwareRevision'], |
| + ['HardwareRevision']] |
| + info = attributes[self._type_3g] |
| + for version_format in version_formats: |
| + if not set(version_format).issubset(set(info)): |
| + continue |
| + # compact all fields into single line with limited space |
| + version_string = ' '.join([info[key] for key in version_format]) |
| + return re.sub('\s+', ' ', version_string) |
| + return self._not_present |
| def get_version_rw_firmware(self): |
| """ |