Implement FRU inventory
Implement parsing of FRU data. This phase omits Multirecord area. Provide access to either just the names or names and extended information. Change-Id: I8b0adf649769a880bf40cbe973864e889f1a6959
This commit is contained in:
		@@ -19,6 +19,7 @@
 | 
			
		||||
import pyghmi.constants as const
 | 
			
		||||
import pyghmi.exceptions as exc
 | 
			
		||||
 | 
			
		||||
import pyghmi.ipmi.fru as fru
 | 
			
		||||
from pyghmi.ipmi.private import session
 | 
			
		||||
import pyghmi.ipmi.sdr as sdr
 | 
			
		||||
 | 
			
		||||
@@ -337,6 +338,35 @@ class Command(object):
 | 
			
		||||
        if 'error' in response:
 | 
			
		||||
            raise exc.IpmiException(response['error'])
 | 
			
		||||
 | 
			
		||||
    def get_inventory_descriptions(self):
 | 
			
		||||
        """Retrieve list of things that could be inventoried
 | 
			
		||||
 | 
			
		||||
        This permits a caller to examine the available items
 | 
			
		||||
        without actually causing the inventory data to be gathered.  It
 | 
			
		||||
        returns an iterable of string descriptions
 | 
			
		||||
        """
 | 
			
		||||
        yield "System"
 | 
			
		||||
        if self._sdr is None:
 | 
			
		||||
            self._sdr = sdr.SDR(self)
 | 
			
		||||
        for fruid in self._sdr.fru:
 | 
			
		||||
            yield self._sdr.fru[fruid].fru_name
 | 
			
		||||
 | 
			
		||||
    def get_inventory(self):
 | 
			
		||||
        """Retrieve inventory of system
 | 
			
		||||
 | 
			
		||||
        Retrieve inventory of the targeted system.  This frequently includes
 | 
			
		||||
        serial numbers, sometimes hardware addresses, sometimes memory modules
 | 
			
		||||
        This function will retrieve whatever the underlying platform provides
 | 
			
		||||
        and apply some structure.  Iterating over the return yields tuples
 | 
			
		||||
        of a name for the inventoried item and
 | 
			
		||||
        """
 | 
			
		||||
        yield ("System", fru.FRU(ipmicmd=self, fruid=0).info)
 | 
			
		||||
        if self._sdr is None:
 | 
			
		||||
            self._sdr = sdr.SDR(self)
 | 
			
		||||
        for fruid in self._sdr.fru:
 | 
			
		||||
            yield (self._sdr.fru[fruid].fru_name, fru.FRU(
 | 
			
		||||
                ipmicmd=self, fruid=fruid, sdr=self._sdr.fru[fruid]).info)
 | 
			
		||||
 | 
			
		||||
    def get_health(self):
 | 
			
		||||
        """Summarize health of managed system
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										309
									
								
								pyghmi/ipmi/fru.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								pyghmi/ipmi/fru.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,309 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
# coding=utf8
 | 
			
		||||
 | 
			
		||||
# Copyright 2015 Lenovo
 | 
			
		||||
#
 | 
			
		||||
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
# you may not use this file except in compliance with the License.
 | 
			
		||||
# You may obtain a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
# Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
 | 
			
		||||
# This module provides access to SDR offered by a BMC
 | 
			
		||||
# This data is common between 'sensors' and 'inventory' modules since SDR
 | 
			
		||||
# is both used to enumerate sensors for sensor commands and FRU ids for FRU
 | 
			
		||||
# commands
 | 
			
		||||
 | 
			
		||||
# For now, we will not offer persistent SDR caching as we do in xCAT's IPMI
 | 
			
		||||
# code.  Will see if it is adequate to advocate for high object reuse in a
 | 
			
		||||
# persistent process for the moment.
 | 
			
		||||
 | 
			
		||||
# Focus is at least initially on the aspects that make the most sense for a
 | 
			
		||||
# remote client to care about.  For example, smbus information is being
 | 
			
		||||
# skipped for now
 | 
			
		||||
 | 
			
		||||
# This file handles parsing of fru format records as presented by IPMI
 | 
			
		||||
# devices.  This format is documented in the 'Platform Management FRU
 | 
			
		||||
# Information Storage Definition (Document Revision 1.2)
 | 
			
		||||
 | 
			
		||||
import pyghmi.exceptions as iexc
 | 
			
		||||
import pyghmi.ipmi.private.spd as spd
 | 
			
		||||
import struct
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
fruepoch = time.mktime(time.strptime('1/1/1996', "%m/%d/%Y"))
 | 
			
		||||
 | 
			
		||||
# This is from SMBIOS specification Table 16
 | 
			
		||||
enclosure_types = {
 | 
			
		||||
    1: 'Other',
 | 
			
		||||
    2: 'Unknown',
 | 
			
		||||
    3: 'Desktop',
 | 
			
		||||
    4: 'Low Profile Desktop',
 | 
			
		||||
    5: 'Pizza Box',
 | 
			
		||||
    6: 'Mini Tower',
 | 
			
		||||
    7: 'Tower',
 | 
			
		||||
    8: 'Portable',
 | 
			
		||||
    9: 'Laptop',
 | 
			
		||||
    0xa: 'Notebook',
 | 
			
		||||
    0xb: 'Hand Held',
 | 
			
		||||
    0xc: 'Docking Station',
 | 
			
		||||
    0xd: 'All in One',
 | 
			
		||||
    0xe: 'Sub Notebook',
 | 
			
		||||
    0xf: 'Space-saving',
 | 
			
		||||
    0x10: 'Lunch Box',
 | 
			
		||||
    0x11: 'Main Server Chassis',
 | 
			
		||||
    0x12: 'Expansion Chassis',
 | 
			
		||||
    0x13: 'SubChassis',
 | 
			
		||||
    0x14: 'Bus Expansion Chassis',
 | 
			
		||||
    0x15: 'Peripheral Chassis',
 | 
			
		||||
    0x16: 'RAID Chassis',
 | 
			
		||||
    0x17: 'Rack Mount Chassis',
 | 
			
		||||
    0x18: 'Sealed-case PC',
 | 
			
		||||
    0x19: 'Multi-system Chassis',
 | 
			
		||||
    0x1a: 'Compact PCI',
 | 
			
		||||
    0x1b: 'Advanced TCA',
 | 
			
		||||
    0x1c: 'Blade',
 | 
			
		||||
    0x1d: 'Blade Enclosure',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def unpack6bitascii(inputdata):
 | 
			
		||||
    # This is a text encoding scheme that seems unique
 | 
			
		||||
    # to IPMI FRU.  It seems to be relatively rare in practice
 | 
			
		||||
    result = ''
 | 
			
		||||
    while len(inputdata) > 0:
 | 
			
		||||
        currchunk = inputdata[:3]
 | 
			
		||||
        del inputdata[:3]
 | 
			
		||||
        currchar = currchunk[0] & 0b111111
 | 
			
		||||
        result += chr(0x20 + currchar)
 | 
			
		||||
        currchar = (currchunk[0] & 0b11000000) >> 6
 | 
			
		||||
        currchar |= (currchunk[1] & 0b1111) << 2
 | 
			
		||||
        result += chr(0x20 + currchar)
 | 
			
		||||
        currchar = (currchunk[1] & 0b1111000) >> 4
 | 
			
		||||
        currchar |= (currchunk[2] & 0b11) << 4
 | 
			
		||||
        result += chr(0x20 + currchar)
 | 
			
		||||
        currchar = (currchunk[2] & 0b11111100) >> 2
 | 
			
		||||
        result += chr(0x20 + currchar)
 | 
			
		||||
    return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def decode_fru_date(datebytes):
 | 
			
		||||
    # Returns ISO
 | 
			
		||||
    datebytes.append(0)
 | 
			
		||||
    minutesfromepoch = struct.unpack('<I', struct.pack('4B', *datebytes))[0]
 | 
			
		||||
    # Some data in the field has had some data less than 800
 | 
			
		||||
    # At this juncture, it's far more likely for this noise
 | 
			
		||||
    # to be incorrect than anything in particular
 | 
			
		||||
    if minutesfromepoch < 800:
 | 
			
		||||
        return None
 | 
			
		||||
    return time.strftime('%Y-%m-%dT%H:%M',
 | 
			
		||||
                         time.gmtime((minutesfromepoch * 60) + fruepoch))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FRU(object):
 | 
			
		||||
    """An object representing structure
 | 
			
		||||
 | 
			
		||||
    FRU (Field Replaceable Unit) is the usual format for inventory in IPMI
 | 
			
		||||
    devices.  This covers most standards compliant inventory data
 | 
			
		||||
    as well as presenting less well defined fields in a structured way.
 | 
			
		||||
 | 
			
		||||
    :param rawdata: A binary string/bytearray of raw data from BMC or dump
 | 
			
		||||
    :param ipmicmd: An ipmi command object to fetch data live
 | 
			
		||||
    :param fruid: The identifier number of the FRU
 | 
			
		||||
    :param sdr: The sdr locator entry to help clarify how to parse data
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, rawdata=None, ipmicmd=None, fruid=0, sdr=None):
 | 
			
		||||
        self.rawfru = rawdata
 | 
			
		||||
        self.databytes = None
 | 
			
		||||
        self.info = None
 | 
			
		||||
        self.sdr = sdr
 | 
			
		||||
        if self.rawfru is not None:
 | 
			
		||||
            self.parsedata()
 | 
			
		||||
        elif ipmicmd is not None:
 | 
			
		||||
            self.ipmicmd = ipmicmd
 | 
			
		||||
            # Use the ipmicmd to fetch the data
 | 
			
		||||
            try:
 | 
			
		||||
                self.fetch_fru(fruid)
 | 
			
		||||
            except iexc.IpmiException as ie:
 | 
			
		||||
                if ie.ipmicode == 203:
 | 
			
		||||
                    self.info = 'Not Present'
 | 
			
		||||
                    return
 | 
			
		||||
            self.parsedata()
 | 
			
		||||
        else:
 | 
			
		||||
            raise TypeError('Either rawdata or ipmicmd must be specified')
 | 
			
		||||
 | 
			
		||||
    def fetch_fru(self, fruid):
 | 
			
		||||
        response = self.ipmicmd.raw_command(
 | 
			
		||||
            netfn=0xa, command=0x10, data=[fruid])
 | 
			
		||||
        if 'error' in response:
 | 
			
		||||
            raise iexc.IpmiException(response['error'], code=response['code'])
 | 
			
		||||
        frusize = response['data'][0] | (response['data'][1] << 8)
 | 
			
		||||
        # In our case, we don't need to think too hard about whether
 | 
			
		||||
        # the FRU is word or byte, we just process what we get back in the
 | 
			
		||||
        # payload
 | 
			
		||||
        chunksize = 240
 | 
			
		||||
        # Selected as it is accomodated by most tested things
 | 
			
		||||
        # and many tested things broke after going much
 | 
			
		||||
        # bigger
 | 
			
		||||
        if chunksize > frusize:
 | 
			
		||||
            chunksize = frusize
 | 
			
		||||
        offset = 0
 | 
			
		||||
        self.rawfru = bytearray([])
 | 
			
		||||
        while chunksize:
 | 
			
		||||
            response = self.ipmicmd.raw_command(
 | 
			
		||||
                netfn=0xa, command=0x11, data=[fruid, offset & 0xff,
 | 
			
		||||
                                               offset >> 8, chunksize])
 | 
			
		||||
            if response['code'] == 201:
 | 
			
		||||
                # if it was too big, back off and try smaller
 | 
			
		||||
                # Try just over half to mitigate the chance of
 | 
			
		||||
                # one request becoming three rather than just two
 | 
			
		||||
                if chunksize == 3:
 | 
			
		||||
                    raise iexc.IpmiException(response['error'])
 | 
			
		||||
                chunksize //= 2
 | 
			
		||||
                chunksize += 2
 | 
			
		||||
                continue
 | 
			
		||||
            elif 'error' in response:
 | 
			
		||||
                raise iexc.IpmiException(response['error'])
 | 
			
		||||
            self.rawfru.extend(response['data'][1:])
 | 
			
		||||
            offset += response['data'][0]
 | 
			
		||||
            if offset + chunksize > frusize:
 | 
			
		||||
                chunksize = frusize - offset
 | 
			
		||||
 | 
			
		||||
    def parsedata(self):
 | 
			
		||||
        self.info = {}
 | 
			
		||||
        rawdata = self.rawfru
 | 
			
		||||
        self.databytes = bytearray(rawdata)
 | 
			
		||||
        if self.sdr is not None:
 | 
			
		||||
            frutype = self.sdr.fru_type_and_modifier >> 8
 | 
			
		||||
            frusubtype = self.sdr.fru_type_and_modifier & 0xff
 | 
			
		||||
            if frutype > 0x10 or frutype < 0x8 or frusubtype not in (0, 1, 2):
 | 
			
		||||
                raise iexc.PyghmiException(
 | 
			
		||||
                    'Unsupported FRU device: {0:x}h, {1:x}h'.format(frutype,
 | 
			
		||||
                                                                    frusubtype
 | 
			
		||||
                                                                    ))
 | 
			
		||||
            elif frusubtype == 1:
 | 
			
		||||
                self.myspd = spd.SPD(self.databytes)
 | 
			
		||||
                self.info = self.myspd.info
 | 
			
		||||
                return
 | 
			
		||||
        if self.databytes[0] != 1:
 | 
			
		||||
            raise iexc.BmcErrorException("Invalid/Unsupported FRU format")
 | 
			
		||||
        # Ignore the internal use even if present.
 | 
			
		||||
        self._parse_chassis()
 | 
			
		||||
        self._parse_board()
 | 
			
		||||
        self._parse_prod()
 | 
			
		||||
        # TODO(jjohnson2): Multi Record area
 | 
			
		||||
 | 
			
		||||
    def _decode_tlv(self, offset, lang=0):
 | 
			
		||||
        currtlv = self.databytes[offset]
 | 
			
		||||
        currlen = currtlv & 0b111111
 | 
			
		||||
        currtype = (currtlv & 0b11000000) >> 6
 | 
			
		||||
        retinfo = self.databytes[offset + 1:offset + currlen]
 | 
			
		||||
        newoffset = offset + currlen + 1
 | 
			
		||||
        if currlen == 0:
 | 
			
		||||
            return None, newoffset
 | 
			
		||||
        if currtype == 0:
 | 
			
		||||
            # return it as a bytearray, not much to be done for it
 | 
			
		||||
            return retinfo, newoffset
 | 
			
		||||
        elif currtype == 3:  # text string
 | 
			
		||||
            if lang == 0:
 | 
			
		||||
                retinfo = retinfo.decode('utf-8')
 | 
			
		||||
            else:
 | 
			
		||||
                retinfo = retinfo.decode('utf-16le')
 | 
			
		||||
            retinfo = retinfo.replace('\x00', '')
 | 
			
		||||
            return retinfo, newoffset
 | 
			
		||||
        elif currtype == 1:  # BCD 'plus'
 | 
			
		||||
            retdata = ''
 | 
			
		||||
            for byte in retinfo:
 | 
			
		||||
                byte = hex(byte).replace('0x', '').replace('a', ' ').replace(
 | 
			
		||||
                    'b', '-').replace('c', '.')
 | 
			
		||||
                retdata += byte
 | 
			
		||||
            return retdata, newoffset
 | 
			
		||||
        elif currtype == 2:  # 6-bit ascii
 | 
			
		||||
            retinfo = unpack6bitascii(retinfo)
 | 
			
		||||
            return retinfo, newoffset
 | 
			
		||||
 | 
			
		||||
    def _parse_chassis(self):
 | 
			
		||||
        offset = 8 * self.databytes[2]
 | 
			
		||||
        if offset == 0:
 | 
			
		||||
            return
 | 
			
		||||
        if self.databytes[offset] & 0b1111 != 1:
 | 
			
		||||
            raise iexc.BmcErrorException("Invallid/Unsupported chassis area")
 | 
			
		||||
        inf = self.info
 | 
			
		||||
        # ignore length field, just process the data
 | 
			
		||||
        inf['chassis_type'] = enclosure_types[self.databytes[offset + 2]]
 | 
			
		||||
        inf['chassis_part_number'], offset = self._decode_tlv(offset + 3)
 | 
			
		||||
        inf['chassis_serial'], offset = self._decode_tlv(offset)
 | 
			
		||||
        inf['chassis_extra'] = []
 | 
			
		||||
        while self.databytes[offset] != 0xc1:
 | 
			
		||||
            fielddata, offset = self._decode_tlv(offset)
 | 
			
		||||
            inf['chassis_extra'].append(fielddata)
 | 
			
		||||
 | 
			
		||||
    def _parse_board(self):
 | 
			
		||||
        offset = 8 * self.databytes[3]
 | 
			
		||||
        if offset == 0:
 | 
			
		||||
            return
 | 
			
		||||
        if self.databytes[offset] & 0b1111 != 1:
 | 
			
		||||
            raise iexc.BmcErrorException("Invalid/Unsupported board info area")
 | 
			
		||||
        inf = self.info
 | 
			
		||||
        language = self.databytes[offset + 2]
 | 
			
		||||
        inf['board_mfg_date'] = decode_fru_date(
 | 
			
		||||
            self.databytes[offset + 3:offset + 6])
 | 
			
		||||
        inf['board_manufacturer'], offset = self._decode_tlv(offset + 6)
 | 
			
		||||
        inf['board_product'], offset = self._decode_tlv(offset, language)
 | 
			
		||||
        inf['board_serial'], offset = self._decode_tlv(offset, language)
 | 
			
		||||
        inf['board_model'], offset = self._decode_tlv(offset, language)
 | 
			
		||||
        _, offset = self._decode_tlv(offset, language)  # decode but discard
 | 
			
		||||
        inf['board_extra'] = []
 | 
			
		||||
        while self.databytes[offset] != 0xc1:
 | 
			
		||||
            fielddata, offset = self._decode_tlv(offset, language)
 | 
			
		||||
            inf['board_extra'].append(fielddata)
 | 
			
		||||
 | 
			
		||||
    def _parse_prod(self):
 | 
			
		||||
        offset = 8 * self.databytes[4]
 | 
			
		||||
        if offset == 0:
 | 
			
		||||
            return
 | 
			
		||||
        inf = self.info
 | 
			
		||||
        language = self.databytes[offset + 2]
 | 
			
		||||
        inf['product_manufacturer'], offset = self._decode_tlv(offset + 3,
 | 
			
		||||
                                                               language)
 | 
			
		||||
        inf['product_name'], offset = self._decode_tlv(offset, language)
 | 
			
		||||
        inf['product_model'], offset = self._decode_tlv(offset, language)
 | 
			
		||||
        inf['product_version'], offset = self._decode_tlv(offset, language)
 | 
			
		||||
        inf['product_serial'], offset = self._decode_tlv(offset, language)
 | 
			
		||||
        inf['product_asset'], offset = self._decode_tlv(offset, language)
 | 
			
		||||
        _, offset = self._decode_tlv(offset, language)
 | 
			
		||||
        inf['product_extra'] = []
 | 
			
		||||
        while self.databytes[offset] != 0xc1:
 | 
			
		||||
            fielddata, offset = self._decode_tlv(offset, language)
 | 
			
		||||
            inf['product_extra'].append(fielddata)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return repr(self.info)
 | 
			
		||||
        # retdata = 'Chassis data\n'
 | 
			
		||||
        # retdata += '   Type: ' + repr(self.chassis_type) + '\n'
 | 
			
		||||
        # retdata += '   Part Number: ' + repr(self.chassis_part_number) + '\n'
 | 
			
		||||
        # retdata += '   Serial Number: ' + repr(self.chassis_serial) + '\n'
 | 
			
		||||
        # retdata += '   Extra: ' + repr(self.chassis_extra) + '\n'
 | 
			
		||||
        # retdata += 'Board data\n'
 | 
			
		||||
        # retdata += '  Manufacturer: ' + repr(self.board_manufacturer) + '\n'
 | 
			
		||||
        # retdata += '   Date: ' + repr(self.board_mfg_date) + '\n'
 | 
			
		||||
        # retdata += '   Product' + repr(self.board_product) + '\n'
 | 
			
		||||
        # retdata += '   Serial: ' + repr(self.board_serial) + '\n'
 | 
			
		||||
        # retdata += '   Model: ' + repr(self.board_model) + '\n'
 | 
			
		||||
        # retdata += '   Extra: ' + repr(self.board_extra) + '\n'
 | 
			
		||||
        # retdata += 'Product data\n'
 | 
			
		||||
        # retdata += '  Manufacturer: ' + repr(self.product_manufacturer)+'\n'
 | 
			
		||||
        # retdata += '  Name: ' + repr(self.product_name) + '\n'
 | 
			
		||||
        # retdata += '  Model: ' + repr(self.product_model) + '\n'
 | 
			
		||||
        # retdata += '  Version: ' + repr(self.product_version) + '\n'
 | 
			
		||||
        # retdata += '  Serial: ' + repr(self.product_serial) + '\n'
 | 
			
		||||
        # retdata += '  Asset: ' + repr(self.product_asset) + '\n'
 | 
			
		||||
        # retdata += '  Extra: ' + repr(self.product_extra) + '\n'
 | 
			
		||||
        # return retdata
 | 
			
		||||
							
								
								
									
										768
									
								
								pyghmi/ipmi/private/spd.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										768
									
								
								pyghmi/ipmi/private/spd.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,768 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
# coding=utf8
 | 
			
		||||
 | 
			
		||||
# Copyright 2015 Lenovo
 | 
			
		||||
#
 | 
			
		||||
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
# you may not use this file except in compliance with the License.
 | 
			
		||||
# You may obtain a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
# http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
# Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
 | 
			
		||||
# This implements parsing of DDR SPD data.  This is offered up in a pass
 | 
			
		||||
# through fashion by some service processors.
 | 
			
		||||
 | 
			
		||||
# For now, just doing DDR3 and DDR4
 | 
			
		||||
 | 
			
		||||
# In many cases, astute readers will note that some of the lookup tables
 | 
			
		||||
# should be a matter of math rather than lookup.  However the SPD
 | 
			
		||||
# specification explicitly reserves values not in the lookup tables for
 | 
			
		||||
# future use.  It has happened, for example, that a spec was amended
 | 
			
		||||
# with discontinuous values for a field that was until that point
 | 
			
		||||
# possible to derive in a formulaic way
 | 
			
		||||
 | 
			
		||||
import struct
 | 
			
		||||
 | 
			
		||||
jedec_ids = [
 | 
			
		||||
    {
 | 
			
		||||
        0x01: "AMD",
 | 
			
		||||
        0x02: "AMI",
 | 
			
		||||
        0x83: "Fairchild",
 | 
			
		||||
        0x04: "Fujitsu",
 | 
			
		||||
        0x85: "GTE",
 | 
			
		||||
        0x86: "Harris",
 | 
			
		||||
        0x07: "Hitachi",
 | 
			
		||||
        0x08: "Inmos",
 | 
			
		||||
        0x89: "Intel",
 | 
			
		||||
        0x8a: "I.T.T.",
 | 
			
		||||
        0x0b: "Intersil",
 | 
			
		||||
        0x8c: "Monolithic Memories",
 | 
			
		||||
        0x0d: "Mostek",
 | 
			
		||||
        0x0e: "Motorola",
 | 
			
		||||
        0x8f: "National",
 | 
			
		||||
        0x10: "NEC",
 | 
			
		||||
        0x91: "RCA",
 | 
			
		||||
        0x92: "Raytheon",
 | 
			
		||||
        0x13: "Conexant (Rockwell)",
 | 
			
		||||
        0x94: "Seeq",
 | 
			
		||||
        0x15: "Philips Semi. (Signetics)",
 | 
			
		||||
        0x16: "Synertek",
 | 
			
		||||
        0x97: "Texas Instruments",
 | 
			
		||||
        0x98: "Toshiba",
 | 
			
		||||
        0x19: "Xicor",
 | 
			
		||||
        0x1a: "Zilog",
 | 
			
		||||
        0x9b: "Eurotechnique",
 | 
			
		||||
        0x1c: "Mitsubishi",
 | 
			
		||||
        0x9d: "Lucent (AT&T)",
 | 
			
		||||
        0x9e: "Exel",
 | 
			
		||||
        0x1f: "Atmel",
 | 
			
		||||
        0x20: "SGS/Thomson",
 | 
			
		||||
        0xa1: "Lattice Semi.",
 | 
			
		||||
        0xa2: "NCR",
 | 
			
		||||
        0x23: "Wafer Scale Integration",
 | 
			
		||||
        0xa4: "IBM",
 | 
			
		||||
        0x25: "Tristar",
 | 
			
		||||
        0x26: "Visic",
 | 
			
		||||
        0xa7: "Intl. CMOS Technology",
 | 
			
		||||
        0xa8: "SSSI",
 | 
			
		||||
        0x29: "Microchip Technology",
 | 
			
		||||
        0x2a: "Ricoh Ltd.",
 | 
			
		||||
        0xab: "VLSI",
 | 
			
		||||
        0x2c: "Micron Technology",
 | 
			
		||||
        0xad: "Hyundai Electronics",
 | 
			
		||||
        0xae: "OKI Semiconductor",
 | 
			
		||||
        0x2f: "ACTEL",
 | 
			
		||||
        0xb0: "Sharp",
 | 
			
		||||
        0x31: "Catalyst",
 | 
			
		||||
        0x32: "Panasonic",
 | 
			
		||||
        0xb3: "IDT",
 | 
			
		||||
        0x34: "Cypress",
 | 
			
		||||
        0xb5: "DEC",
 | 
			
		||||
        0xb6: "LSI Logic",
 | 
			
		||||
        0x37: "Zarlink",
 | 
			
		||||
        0x38: "UTMC",
 | 
			
		||||
        0xb9: "Thinking Machine",
 | 
			
		||||
        0xba: "Thomson CSF",
 | 
			
		||||
        0x3b: "Integrated CMOS(Vertex)",
 | 
			
		||||
        0xbc: "Honeywell",
 | 
			
		||||
        0x3d: "Tektronix",
 | 
			
		||||
        0x3e: "Sun Microsystems",
 | 
			
		||||
        0xbf: "SST",
 | 
			
		||||
        0x40: "MOSEL",
 | 
			
		||||
        0xc1: "Infineon",
 | 
			
		||||
        0xc2: "Macronix",
 | 
			
		||||
        0x43: "Xerox",
 | 
			
		||||
        0xc4: "Plus Logic",
 | 
			
		||||
        0x45: "SunDisk",
 | 
			
		||||
        0x46: "Elan Circuit Tech.",
 | 
			
		||||
        0xc7: "European Silicon Str.",
 | 
			
		||||
        0xc8: "Apple Computer",
 | 
			
		||||
        0xc9: "Xilinx",
 | 
			
		||||
        0x4a: "Compaq",
 | 
			
		||||
        0xcb: "Protocol Engines",
 | 
			
		||||
        0x4c: "SCI",
 | 
			
		||||
        0xcd: "Seiko Instruments",
 | 
			
		||||
        0xce: "Samsung",
 | 
			
		||||
        0x4f: "I3 Design System",
 | 
			
		||||
        0xd0: "Klic",
 | 
			
		||||
        0x51: "Crosspoint Solutions",
 | 
			
		||||
        0x52: "Alliance Semiconductor",
 | 
			
		||||
        0xd3: "Tandem",
 | 
			
		||||
        0x54: "Hewlett-Packard",
 | 
			
		||||
        0xd5: "Intg. Silicon Solutions",
 | 
			
		||||
        0xd6: "Brooktree",
 | 
			
		||||
        0x57: "New Media",
 | 
			
		||||
        0x58: "MHS Electronic",
 | 
			
		||||
        0xd9: "Performance Semi.",
 | 
			
		||||
        0xda: "Winbond Electronic",
 | 
			
		||||
        0x5b: "Kawasaki Steel",
 | 
			
		||||
        0xdc: "Bright Micro",
 | 
			
		||||
        0x5d: "TECMAR",
 | 
			
		||||
        0x5e: "Exar",
 | 
			
		||||
        0xdf: "PCMCIA",
 | 
			
		||||
        0xe0: "LG Semiconductor",
 | 
			
		||||
        0x61: "Northern Telecom",
 | 
			
		||||
        0x62: "Sanyo",
 | 
			
		||||
        0xe3: "Array Microsystems",
 | 
			
		||||
        0x64: "Crystal Semiconductor",
 | 
			
		||||
        0xe5: "Analog Devices",
 | 
			
		||||
        0xe6: "PMC-Sierra",
 | 
			
		||||
        0x67: "Asparix",
 | 
			
		||||
        0x68: "Convex Computer",
 | 
			
		||||
        0xe9: "Quality Semiconductor",
 | 
			
		||||
        0xea: "Nimbus Technology",
 | 
			
		||||
        0x6b: "Transwitch",
 | 
			
		||||
        0xec: "Micronas (ITT Intermetall)",
 | 
			
		||||
        0x6d: "Cannon",
 | 
			
		||||
        0x6e: "Altera",
 | 
			
		||||
        0xef: "NEXCOM",
 | 
			
		||||
        0x70: "QUALCOMM",
 | 
			
		||||
        0xf1: "Sony",
 | 
			
		||||
        0xf2: "Cray Research",
 | 
			
		||||
        0x73: "AMS (Austria Micro)",
 | 
			
		||||
        0xf4: "Vitesse",
 | 
			
		||||
        0x75: "Aster Electronics",
 | 
			
		||||
        0x76: "Bay Networks (Synoptic)",
 | 
			
		||||
        0xf7: "Zentrum",
 | 
			
		||||
        0xf8: "TRW",
 | 
			
		||||
        0x79: "Thesys",
 | 
			
		||||
        0x7a: "Solbourne Computer",
 | 
			
		||||
        0xfb: "Allied-Signal",
 | 
			
		||||
        0x7c: "Dialog",
 | 
			
		||||
        0xfd: "Media Vision",
 | 
			
		||||
        0xfe: "Level One Communication",
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        0x01: "Cirrus Logic",
 | 
			
		||||
        0x02: "National Instruments",
 | 
			
		||||
        0x83: "ILC Data Device",
 | 
			
		||||
        0x04: "Alcatel Mietec",
 | 
			
		||||
        0x85: "Micro Linear",
 | 
			
		||||
        0x86: "Univ. of NC",
 | 
			
		||||
        0x07: "JTAG Technologies",
 | 
			
		||||
        0x08: "Loral",
 | 
			
		||||
        0x89: "Nchip",
 | 
			
		||||
        0x8A: "Galileo Tech",
 | 
			
		||||
        0x0B: "Bestlink Systems",
 | 
			
		||||
        0x8C: "Graychip",
 | 
			
		||||
        0x0D: "GENNUM",
 | 
			
		||||
        0x0E: "VideoLogic",
 | 
			
		||||
        0x8F: "Robert Bosch",
 | 
			
		||||
        0x10: "Chip Express",
 | 
			
		||||
        0x91: "DATARAM",
 | 
			
		||||
        0x92: "United Microelec Corp.",
 | 
			
		||||
        0x13: "TCSI",
 | 
			
		||||
        0x94: "Smart Modular",
 | 
			
		||||
        0x15: "Hughes Aircraft",
 | 
			
		||||
        0x16: "Lanstar Semiconductor",
 | 
			
		||||
        0x97: "Qlogic",
 | 
			
		||||
        0x98: "Kingston",
 | 
			
		||||
        0x19: "Music Semi",
 | 
			
		||||
        0x1A: "Ericsson Components",
 | 
			
		||||
        0x9B: "SpaSE",
 | 
			
		||||
        0x1C: "Eon Silicon Devices",
 | 
			
		||||
        0x9D: "Programmable Micro Corp",
 | 
			
		||||
        0x9E: "DoD",
 | 
			
		||||
        0x1F: "Integ. Memories Tech.",
 | 
			
		||||
        0x20: "Corollary Inc.",
 | 
			
		||||
        0xA1: "Dallas Semiconductor",
 | 
			
		||||
        0xA2: "Omnivision",
 | 
			
		||||
        0x23: "EIV(Switzerland)",
 | 
			
		||||
        0xA4: "Novatel Wireless",
 | 
			
		||||
        0x25: "Zarlink (formerly Mitel)",
 | 
			
		||||
        0x26: "Clearpoint",
 | 
			
		||||
        0xA7: "Cabletron",
 | 
			
		||||
        0xA8: "Silicon Technology",
 | 
			
		||||
        0x29: "Vanguard",
 | 
			
		||||
        0x2A: "Hagiwara Sys-Com",
 | 
			
		||||
        0xAB: "Vantis",
 | 
			
		||||
        0x2C: "Celestica",
 | 
			
		||||
        0xAD: "Century",
 | 
			
		||||
        0xAE: "Hal Computers",
 | 
			
		||||
        0x2F: "Rohm Company Ltd.",
 | 
			
		||||
        0xB0: "Juniper Networks",
 | 
			
		||||
        0x31: "Libit Signal Processing",
 | 
			
		||||
        0x32: "Enhanced Memories Inc.",
 | 
			
		||||
        0xB3: "Tundra Semiconductor",
 | 
			
		||||
        0x34: "Adaptec Inc.",
 | 
			
		||||
        0xB5: "LightSpeed Semi.",
 | 
			
		||||
        0xB6: "ZSP Corp.",
 | 
			
		||||
        0x37: "AMIC Technology",
 | 
			
		||||
        0x38: "Adobe Systems",
 | 
			
		||||
        0xB9: "Dynachip",
 | 
			
		||||
        0xBA: "PNY Electronics",
 | 
			
		||||
        0x3B: "Newport Digital",
 | 
			
		||||
        0xBC: "MMC Networks",
 | 
			
		||||
        0x3D: "T Square",
 | 
			
		||||
        0x3E: "Seiko Epson",
 | 
			
		||||
        0xBF: "Broadcom",
 | 
			
		||||
        0x40: "Viking Components",
 | 
			
		||||
        0xC1: "V3 Semiconductor",
 | 
			
		||||
        0xC2: "Flextronics (formerly Orbit)",
 | 
			
		||||
        0x43: "Suwa Electronics",
 | 
			
		||||
        0xC4: "Transmeta",
 | 
			
		||||
        0x45: "Micron CMS",
 | 
			
		||||
        0x46: "American Computer & Digital Components Inc",
 | 
			
		||||
        0xC7: "Enhance 3000 Inc",
 | 
			
		||||
        0xC8: "Tower Semiconductor",
 | 
			
		||||
        0x49: "CPU Design",
 | 
			
		||||
        0x4A: "Price Point",
 | 
			
		||||
        0xCB: "Maxim Integrated Product",
 | 
			
		||||
        0x4C: "Tellabs",
 | 
			
		||||
        0xCD: "Centaur Technology",
 | 
			
		||||
        0xCE: "Unigen Corporation",
 | 
			
		||||
        0x4F: "Transcend Information",
 | 
			
		||||
        0xD0: "Memory Card Technology",
 | 
			
		||||
        0x51: "CKD Corporation Ltd.",
 | 
			
		||||
        0x52: "Capital Instruments, Inc.",
 | 
			
		||||
        0xD3: "Aica Kogyo, Ltd.",
 | 
			
		||||
        0x54: "Linvex Technology",
 | 
			
		||||
        0xD5: "MSC Vertriebs GmbH",
 | 
			
		||||
        0xD6: "AKM Company, Ltd.",
 | 
			
		||||
        0x57: "Dynamem, Inc.",
 | 
			
		||||
        0x58: "NERA ASA",
 | 
			
		||||
        0xD9: "GSI Technology",
 | 
			
		||||
        0xDA: "Dane-Elec (C Memory)",
 | 
			
		||||
        0x5B: "Acorn Computers",
 | 
			
		||||
        0xDC: "Lara Technology",
 | 
			
		||||
        0x5D: "Oak Technology, Inc.",
 | 
			
		||||
        0x5E: "Itec Memory",
 | 
			
		||||
        0xDF: "Tanisys Technology",
 | 
			
		||||
        0xE0: "Truevision",
 | 
			
		||||
        0x61: "Wintec Industries",
 | 
			
		||||
        0x62: "Super PC Memory",
 | 
			
		||||
        0xE3: "MGV Memory",
 | 
			
		||||
        0x64: "Galvantech",
 | 
			
		||||
        0xE5: "Gadzoox Nteworks",
 | 
			
		||||
        0xE6: "Multi Dimensional Cons.",
 | 
			
		||||
        0x67: "GateField",
 | 
			
		||||
        0x68: "Integrated Memory System",
 | 
			
		||||
        0xE9: "Triscend",
 | 
			
		||||
        0xEA: "XaQti",
 | 
			
		||||
        0x6B: "Goldenram",
 | 
			
		||||
        0xEC: "Clear Logic",
 | 
			
		||||
        0x6D: "Cimaron Communications",
 | 
			
		||||
        0x6E: "Nippon Steel Semi. Corp.",
 | 
			
		||||
        0xEF: "Advantage Memory",
 | 
			
		||||
        0x70: "AMCC",
 | 
			
		||||
        0xF1: "LeCroy",
 | 
			
		||||
        0xF2: "Yamaha Corporation",
 | 
			
		||||
        0x73: "Digital Microwave",
 | 
			
		||||
        0xF4: "NetLogic Microsystems",
 | 
			
		||||
        0x75: "MIMOS Semiconductor",
 | 
			
		||||
        0x76: "Advanced Fibre",
 | 
			
		||||
        0xF7: "BF Goodrich Data.",
 | 
			
		||||
        0xF8: "Epigram",
 | 
			
		||||
        0x79: "Acbel Polytech Inc.",
 | 
			
		||||
        0x7A: "Apacer Technology",
 | 
			
		||||
        0xFB: "Admor Memory",
 | 
			
		||||
        0x7C: "FOXCONN",
 | 
			
		||||
        0xFD: "Quadratics Superconductor",
 | 
			
		||||
        0xFE: "3COM",
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        0x01: "Camintonn Corporation",
 | 
			
		||||
        0x02: "ISOA Incorporated",
 | 
			
		||||
        0x83: "Agate Semiconductor",
 | 
			
		||||
        0x04: "ADMtek Incorporated",
 | 
			
		||||
        0x85: "HYPERTEC",
 | 
			
		||||
        0x86: "Adhoc Technologies",
 | 
			
		||||
        0x07: "MOSAID Technologies",
 | 
			
		||||
        0x08: "Ardent Technologies",
 | 
			
		||||
        0x89: "Switchcore",
 | 
			
		||||
        0x8A: "Cisco Systems, Inc.",
 | 
			
		||||
        0x0B: "Allayer Technologies",
 | 
			
		||||
        0x8C: "WorkX AG",
 | 
			
		||||
        0x0D: "Oasis Semiconductor",
 | 
			
		||||
        0x0E: "Novanet Semiconductor",
 | 
			
		||||
        0x8F: "E-M Solutions",
 | 
			
		||||
        0x10: "Power General",
 | 
			
		||||
        0x91: "Advanced Hardware Arch.",
 | 
			
		||||
        0x92: "Inova Semiconductors GmbH",
 | 
			
		||||
        0x13: "Telocity",
 | 
			
		||||
        0x94: "Delkin Devices",
 | 
			
		||||
        0x15: "Symagery Microsystems",
 | 
			
		||||
        0x16: "C-Port Corporation",
 | 
			
		||||
        0x97: "SiberCore Technologies",
 | 
			
		||||
        0x98: "Southland Microsystems",
 | 
			
		||||
        0x19: "Malleable Technologies",
 | 
			
		||||
        0x1A: "Kendin Communications",
 | 
			
		||||
        0x9B: "Great Technology Microcomputer",
 | 
			
		||||
        0x1C: "Sanmina Corporation",
 | 
			
		||||
        0x9D: "HADCO Corporation",
 | 
			
		||||
        0x9E: "Corsair",
 | 
			
		||||
        0x1F: "Actrans System Inc.",
 | 
			
		||||
        0x20: "ALPHA Technologies",
 | 
			
		||||
        0xA1: "Cygnal Integrated Products Incorporated",
 | 
			
		||||
        0xA2: "Artesyn Technologies",
 | 
			
		||||
        0x23: "Align Manufacturing",
 | 
			
		||||
        0xA4: "Peregrine Semiconductor",
 | 
			
		||||
        0x25: "Chameleon Systems",
 | 
			
		||||
        0x26: "Aplus Flash Technology",
 | 
			
		||||
        0xA7: "MIPS Technologies",
 | 
			
		||||
        0xA8: "Chrysalis ITS",
 | 
			
		||||
        0x29: "ADTEC Corporation",
 | 
			
		||||
        0x2A: "Kentron Technologies",
 | 
			
		||||
        0xAB: "Win Technologies",
 | 
			
		||||
        0x2C: "ASIC Designs Inc",
 | 
			
		||||
        0xAD: "Extreme Packet Devices",
 | 
			
		||||
        0xAE: "RF Micro Devices",
 | 
			
		||||
        0x2F: "Siemens AG",
 | 
			
		||||
        0xB0: "Sarnoff Corporation",
 | 
			
		||||
        0x31: "Itautec Philco SA",
 | 
			
		||||
        0x32: "Radiata Inc.",
 | 
			
		||||
        0xB3: "Benchmark Elect. (AVEX)",
 | 
			
		||||
        0x34: "Legend",
 | 
			
		||||
        0xB5: "SpecTek Incorporated",
 | 
			
		||||
        0xB6: "Hi/fn",
 | 
			
		||||
        0x37: "Enikia Incorporated",
 | 
			
		||||
        0x38: "SwitchOn Networks",
 | 
			
		||||
        0xB9: "AANetcom Incorporated",
 | 
			
		||||
        0xBA: "Micro Memory Bank",
 | 
			
		||||
        0x3B: "ESS Technology",
 | 
			
		||||
        0xBC: "Virata Corporation",
 | 
			
		||||
        0x3D: "Excess Bandwidth",
 | 
			
		||||
        0x3E: "West Bay Semiconductor",
 | 
			
		||||
        0xBF: "DSP Group",
 | 
			
		||||
        0x40: "Newport Communications",
 | 
			
		||||
        0xC1: "Chip2Chip Incorporated",
 | 
			
		||||
        0xC2: "Phobos Corporation",
 | 
			
		||||
        0x43: "Intellitech Corporation",
 | 
			
		||||
        0xC4: "Nordic VLSI ASA",
 | 
			
		||||
        0x45: "Ishoni Networks",
 | 
			
		||||
        0x46: "Silicon Spice",
 | 
			
		||||
        0xC7: "Alchemy Semiconductor",
 | 
			
		||||
        0xC8: "Agilent Technologies",
 | 
			
		||||
        0x49: "Centillium Communications",
 | 
			
		||||
        0x4A: "W.L. Gore",
 | 
			
		||||
        0xCB: "HanBit Electronics",
 | 
			
		||||
        0x4C: "GlobeSpan",
 | 
			
		||||
        0xCD: "Element 14",
 | 
			
		||||
        0xCE: "Pycon",
 | 
			
		||||
        0x4F: "Saifun Semiconductors",
 | 
			
		||||
        0xD0: "Sibyte, Incorporated",
 | 
			
		||||
        0x51: "MetaLink Technologies",
 | 
			
		||||
        0x52: "Feiya Technology",
 | 
			
		||||
        0xD3: "I & C Technology",
 | 
			
		||||
        0x54: "Shikatronics",
 | 
			
		||||
        0xD5: "Elektrobit",
 | 
			
		||||
        0xD6: "Megic",
 | 
			
		||||
        0x57: "Com-Tier",
 | 
			
		||||
        0x58: "Malaysia Micro Solutions",
 | 
			
		||||
        0xD9: "Hyperchip",
 | 
			
		||||
        0xDA: "Gemstone Communications",
 | 
			
		||||
        0x5B: "Anadyne Microelectronics",
 | 
			
		||||
        0xDC: "3ParData",
 | 
			
		||||
        0x5D: "Mellanox Technologies",
 | 
			
		||||
        0x5E: "Tenx Technologies",
 | 
			
		||||
        0xDF: "Helix AG",
 | 
			
		||||
        0xE0: "Domosys",
 | 
			
		||||
        0x61: "Skyup Technology",
 | 
			
		||||
        0x62: "HiNT Corporation",
 | 
			
		||||
        0xE3: "Chiaro",
 | 
			
		||||
        0x64: "MCI Computer GMBH",
 | 
			
		||||
        0xE5: "Exbit Technology A/S",
 | 
			
		||||
        0xE6: "Integrated Technology Express",
 | 
			
		||||
        0x67: "AVED Memory",
 | 
			
		||||
        0x68: "Legerity",
 | 
			
		||||
        0xE9: "Jasmine Networks",
 | 
			
		||||
        0xEA: "Caspian Networks",
 | 
			
		||||
        0x6B: "nCUBE",
 | 
			
		||||
        0xEC: "Silicon Access Networks",
 | 
			
		||||
        0x6D: "FDK Corporation",
 | 
			
		||||
        0x6E: "High Bandwidth Access",
 | 
			
		||||
        0xEF: "MultiLink Technology",
 | 
			
		||||
        0x70: "BRECIS",
 | 
			
		||||
        0xF1: "World Wide Packets",
 | 
			
		||||
        0xF2: "APW",
 | 
			
		||||
        0x73: "Chicory Systems",
 | 
			
		||||
        0xF4: "Xstream Logic",
 | 
			
		||||
        0x75: "Fast-Chip",
 | 
			
		||||
        0x76: "Zucotto Wireless",
 | 
			
		||||
        0xF7: "Realchip",
 | 
			
		||||
        0xF8: "Galaxy Power",
 | 
			
		||||
        0x79: "eSilicon",
 | 
			
		||||
        0x7A: "Morphics Technology",
 | 
			
		||||
        0xFB: "Accelerant Networks",
 | 
			
		||||
        0x7C: "Silicon Wave",
 | 
			
		||||
        0xFD: "SandCraft",
 | 
			
		||||
        0xFE: "Elpida",
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        0x01: "Solectron",
 | 
			
		||||
        0x02: "Optosys Technologies",
 | 
			
		||||
        0x83: "Buffalo (Formerly Melco)",
 | 
			
		||||
        0x04: "TriMedia Technologies",
 | 
			
		||||
        0x85: "Cyan Technologies",
 | 
			
		||||
        0x86: "Global Locate",
 | 
			
		||||
        0x07: "Optillion",
 | 
			
		||||
        0x08: "Terago Communications",
 | 
			
		||||
        0x89: "Ikanos Communications",
 | 
			
		||||
        0x8A: "Princeton Technology",
 | 
			
		||||
        0x0B: "Nanya Technology",
 | 
			
		||||
        0x8C: "Elite Flash Storage",
 | 
			
		||||
        0x0D: "Mysticom",
 | 
			
		||||
        0x0E: "LightSand Communications",
 | 
			
		||||
        0x8F: "ATI Technologies",
 | 
			
		||||
        0x10: "Agere Systems",
 | 
			
		||||
        0x91: "NeoMagic",
 | 
			
		||||
        0x92: "AuroraNetics",
 | 
			
		||||
        0x13: "Golden Empire",
 | 
			
		||||
        0x94: "Muskin",
 | 
			
		||||
        0x15: "Tioga Technologies",
 | 
			
		||||
        0x16: "Netlist",
 | 
			
		||||
        0x97: "TeraLogic",
 | 
			
		||||
        0x98: "Cicada Semiconductor",
 | 
			
		||||
        0x19: "Centon Electronics",
 | 
			
		||||
        0x1A: "Tyco Electronics",
 | 
			
		||||
        0x9B: "Magis Works",
 | 
			
		||||
        0x1C: "Zettacom",
 | 
			
		||||
        0x9D: "Cogency Semiconductor",
 | 
			
		||||
        0x9E: "Chipcon AS",
 | 
			
		||||
        0x1F: "Aspex Technology",
 | 
			
		||||
        0x20: "F5 Networks",
 | 
			
		||||
        0xA1: "Programmable Silicon Solutions",
 | 
			
		||||
        0xA2: "ChipWrights",
 | 
			
		||||
        0x23: "Acorn Networks",
 | 
			
		||||
        0xA4: "Quicklogic",
 | 
			
		||||
        0x25: "Kingmax Semiconductor",
 | 
			
		||||
        0x26: "BOPS",
 | 
			
		||||
        0xA7: "Flasys",
 | 
			
		||||
        0xA8: "BitBlitz Communications",
 | 
			
		||||
        0x29: "eMemory Technology",
 | 
			
		||||
        0x2A: "Procket Networks",
 | 
			
		||||
        0xAB: "Purple Ray",
 | 
			
		||||
        0x2C: "Trebia Networks",
 | 
			
		||||
        0xAD: "Delta Electronics",
 | 
			
		||||
        0xAE: "Onex Communications",
 | 
			
		||||
        0x2F: "Ample Communications",
 | 
			
		||||
        0xB0: "Memory Experts Intl",
 | 
			
		||||
        0x31: "Astute Networks",
 | 
			
		||||
        0x32: "Azanda Network Devices",
 | 
			
		||||
        0xB3: "Dibcom",
 | 
			
		||||
        0x34: "Tekmos",
 | 
			
		||||
        0xB5: "API NetWorks",
 | 
			
		||||
        0xB6: "Bay Microsystems",
 | 
			
		||||
        0x37: "Firecron Ltd",
 | 
			
		||||
        0x38: "Resonext Communications",
 | 
			
		||||
        0xB9: "Tachys Technologies",
 | 
			
		||||
        0xBA: "Equator Technology",
 | 
			
		||||
        0x3B: "Concept Computer",
 | 
			
		||||
        0xBC: "SILCOM",
 | 
			
		||||
        0x3D: "3Dlabs",
 | 
			
		||||
        0x3E: "ct Magazine",
 | 
			
		||||
        0xBF: "Sanera Systems",
 | 
			
		||||
        0x40: "Silicon Packets",
 | 
			
		||||
        0xC1: "Viasystems Group",
 | 
			
		||||
        0xC2: "Simtek",
 | 
			
		||||
        0x43: "Semicon Devices Singapore",
 | 
			
		||||
        0xC4: "Satron Handelsges",
 | 
			
		||||
        0x45: "Improv Systems",
 | 
			
		||||
        0x46: "INDUSYS GmbH",
 | 
			
		||||
        0xC7: "Corrent",
 | 
			
		||||
        0xC8: "Infrant Technologies",
 | 
			
		||||
        0x49: "Ritek Corp",
 | 
			
		||||
        0x4A: "empowerTel Networks",
 | 
			
		||||
        0xCB: "Hypertec",
 | 
			
		||||
        0x4C: "Cavium Networks",
 | 
			
		||||
        0xCD: "PLX Technology",
 | 
			
		||||
        0xCE: "Massana Design",
 | 
			
		||||
        0x4F: "Intrinsity",
 | 
			
		||||
        0xD0: "Valence Semiconductor",
 | 
			
		||||
        0x51: "Terawave Communications",
 | 
			
		||||
        0x52: "IceFyre Semiconductor",
 | 
			
		||||
        0xD3: "Primarion",
 | 
			
		||||
        0x54: "Picochip Designs Ltd",
 | 
			
		||||
        0xD5: "Silverback Systems",
 | 
			
		||||
        0xD6: "Jade Star Technologies",
 | 
			
		||||
        0x57: "Pijnenburg Securealink",
 | 
			
		||||
        0x58: "MemorySolutioN",
 | 
			
		||||
        0xD9: "Cambridge Silicon Radio",
 | 
			
		||||
        0xDA: "Swissbit",
 | 
			
		||||
        0x5B: "Nazomi Communications",
 | 
			
		||||
        0xDC: "eWave System",
 | 
			
		||||
        0x5D: "Rockwell Collins",
 | 
			
		||||
        0x5E: "PAION",
 | 
			
		||||
        0xDF: "Alphamosaic Ltd",
 | 
			
		||||
        0xE0: "Sandburst",
 | 
			
		||||
        0x61: "SiCon Video",
 | 
			
		||||
        0x62: "NanoAmp Solutions",
 | 
			
		||||
        0xE3: "Ericsson Technology",
 | 
			
		||||
        0x64: "PrairieComm",
 | 
			
		||||
        0xE5: "Mitac International",
 | 
			
		||||
        0xE6: "Layer N Networks",
 | 
			
		||||
        0x67: "Atsana Semiconductor",
 | 
			
		||||
        0x68: "Allegro Networks",
 | 
			
		||||
        0xE9: "Marvell Semiconductors",
 | 
			
		||||
        0xEA: "Netergy Microelectronic",
 | 
			
		||||
        0x6B: "NVIDIA",
 | 
			
		||||
        0xEC: "Internet Machines",
 | 
			
		||||
        0x6D: "Peak Electronics",
 | 
			
		||||
        0xEF: "Accton Technology",
 | 
			
		||||
        0x70: "Teradiant Networks",
 | 
			
		||||
        0xF1: "Europe Technologies",
 | 
			
		||||
        0xF2: "Cortina Systems",
 | 
			
		||||
        0x73: "RAM Components",
 | 
			
		||||
        0xF4: "Raqia Networks",
 | 
			
		||||
        0x75: "ClearSpeed",
 | 
			
		||||
        0x76: "Matsushita Battery",
 | 
			
		||||
        0xF7: "Xelerated",
 | 
			
		||||
        0xF8: "SimpleTech",
 | 
			
		||||
        0x79: "Utron Technology",
 | 
			
		||||
        0x7A: "Astec International",
 | 
			
		||||
        0xFB: "AVM gmbH",
 | 
			
		||||
        0x7C: "Redux Communications",
 | 
			
		||||
        0xFD: "Dot Hill Systems",
 | 
			
		||||
        0xFE: "TeraChip",
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        0x01: "T-RAM Incorporated",
 | 
			
		||||
        0x02: "Innovics Wireless",
 | 
			
		||||
        0x83: "Teknovus",
 | 
			
		||||
        0x04: "KeyEye Communications",
 | 
			
		||||
        0x85: "Runcom Technologies",
 | 
			
		||||
        0x86: "RedSwitch",
 | 
			
		||||
        0x07: "Dotcast",
 | 
			
		||||
        0x08: "Silicon Mountain Memory",
 | 
			
		||||
        0x89: "Signia Technologies",
 | 
			
		||||
        0x8A: "Pixim",
 | 
			
		||||
        0x0B: "Galazar Networks",
 | 
			
		||||
        0x8C: "White Electronic Designs",
 | 
			
		||||
        0x0D: "Patriot Scientific",
 | 
			
		||||
        0x0E: "Neoaxiom Corporation",
 | 
			
		||||
        0x8F: "3Y Power Technology",
 | 
			
		||||
        0x10: "Europe Technologies",
 | 
			
		||||
        0x91: "Potentia Power Systems",
 | 
			
		||||
        0x92: "C-guys Incorporated",
 | 
			
		||||
        0x13: "Digital Communications Technology Incorporated",
 | 
			
		||||
        0x94: "Silicon-Based Technology",
 | 
			
		||||
        0x15: "Fulcrum Microsystems",
 | 
			
		||||
        0x16: "Positivo Informatica Ltd",
 | 
			
		||||
        0x97: "XIOtech Corporation",
 | 
			
		||||
        0x98: "PortalPlayer",
 | 
			
		||||
        0x19: "Zhiying Software",
 | 
			
		||||
        0x1A: "Direct2Data",
 | 
			
		||||
        0x9B: "Phonex Broadband",
 | 
			
		||||
        0x1C: "Skyworks Solutions",
 | 
			
		||||
        0x9D: "Entropic Communications",
 | 
			
		||||
        0x9E: "Pacific Force Technology",
 | 
			
		||||
        0x1F: "Zensys A/S",
 | 
			
		||||
        0x20: "Legend Silicon Corp.",
 | 
			
		||||
        0xA1: "sci-worx GmbH",
 | 
			
		||||
        0xA2: "Oasis Silicon Systems",
 | 
			
		||||
        0x23: "Renesas Technology",
 | 
			
		||||
        0xA4: "Raza Microelectronics",
 | 
			
		||||
        0x25: "Phyworks",
 | 
			
		||||
        0x26: "MediaTek",
 | 
			
		||||
        0xA7: "Non-cents Productions",
 | 
			
		||||
        0xA8: "US Modular",
 | 
			
		||||
        0x29: "Wintegra Ltd",
 | 
			
		||||
        0x2A: "Mathstar",
 | 
			
		||||
        0xAB: "StarCore",
 | 
			
		||||
        0x2C: "Oplus Technologies",
 | 
			
		||||
        0xAD: "Mindspeed",
 | 
			
		||||
        0xAE: "Just Young Computer",
 | 
			
		||||
        0x2F: "Radia Communications",
 | 
			
		||||
        0xB0: "OCZ",
 | 
			
		||||
        0x31: "Emuzed",
 | 
			
		||||
        0x32: "LOGIC Devices",
 | 
			
		||||
        0xB3: "Inphi Corporation",
 | 
			
		||||
        0x34: "Quake Technologies",
 | 
			
		||||
        0xB5: "Vixel",
 | 
			
		||||
        0xB6: "SolusTek",
 | 
			
		||||
        0x37: "Kongsberg Maritime",
 | 
			
		||||
        0x38: "Faraday Technology",
 | 
			
		||||
        0xB9: "Altium Ltd.",
 | 
			
		||||
        0xBA: "Insyte",
 | 
			
		||||
        0x3B: "ARM Ltd.",
 | 
			
		||||
        0xBC: "DigiVision",
 | 
			
		||||
        0x3D: "Vativ Technologies",
 | 
			
		||||
        0x3E: "Endicott Interconnect Technologies",
 | 
			
		||||
        0xBF: "Pericom",
 | 
			
		||||
        0x40: "Bandspeed",
 | 
			
		||||
        0xC1: "LeWiz Communications",
 | 
			
		||||
        0xC2: "CPU Technology",
 | 
			
		||||
        0x43: "Ramaxel Technology",
 | 
			
		||||
        0xC4: "DSP Group",
 | 
			
		||||
        0x45: "Axis Communications",
 | 
			
		||||
        0x46: "Legacy Electronics",
 | 
			
		||||
        0xC7: "Chrontel",
 | 
			
		||||
        0xC8: "Powerchip Semiconductor",
 | 
			
		||||
        0x49: "MobilEye Technologies",
 | 
			
		||||
        0x4A: "Excel Semiconductor",
 | 
			
		||||
        0xCB: "A-DATA Technology",
 | 
			
		||||
        0x4C: "VirtualDigm",
 | 
			
		||||
    },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
memory_types = {
 | 
			
		||||
    1: "STD FPM DRAM",
 | 
			
		||||
    2: "EDO",
 | 
			
		||||
    3: "Pipelined Nibble",
 | 
			
		||||
    4: "SDRAM",
 | 
			
		||||
    5: "ROM",
 | 
			
		||||
    6: "DDR SGRAM",
 | 
			
		||||
    7: "DDR SDRAM",
 | 
			
		||||
    8: "DDR2 SDRAM",
 | 
			
		||||
    9: "DDR2 SDRAM FB-DIMM",
 | 
			
		||||
    10: "DDR2 SDRAM FB-DIMM PROBE",
 | 
			
		||||
    11: "DDR3 SDRAM",
 | 
			
		||||
    12: "DDR4 SDRAM",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module_types = {
 | 
			
		||||
    1: "RDIMM",
 | 
			
		||||
    2: "UDIMM",
 | 
			
		||||
    3: "SODIMM",
 | 
			
		||||
    4: "Micro-DIMM",
 | 
			
		||||
    5: "Mini-RDIMM",
 | 
			
		||||
    6: "Mini-UDIMM",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ddr3_module_capacity = {
 | 
			
		||||
    0: 256,
 | 
			
		||||
    1: 512,
 | 
			
		||||
    2: 1024,
 | 
			
		||||
    3: 2048,
 | 
			
		||||
    4: 4096,
 | 
			
		||||
    5: 8192,
 | 
			
		||||
    6: 16384,
 | 
			
		||||
    7: 32768,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ddr3_dev_width = {
 | 
			
		||||
    0: 4,
 | 
			
		||||
    1: 8,
 | 
			
		||||
    2: 16,
 | 
			
		||||
    3: 32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ddr3_ranks = {
 | 
			
		||||
    0: 1,
 | 
			
		||||
    1: 2,
 | 
			
		||||
    2: 3,
 | 
			
		||||
    3: 4
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ddr3_bus_width = {
 | 
			
		||||
    0: 8,
 | 
			
		||||
    1: 16,
 | 
			
		||||
    2: 32,
 | 
			
		||||
    3: 64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
speed_by_clock = {
 | 
			
		||||
    800: 6400,
 | 
			
		||||
    1066: 8500,
 | 
			
		||||
    1333: 10600,
 | 
			
		||||
    1600: 12800,
 | 
			
		||||
    1867: 14900,
 | 
			
		||||
    2132: 17000,
 | 
			
		||||
    2133: 17000,
 | 
			
		||||
    2134: 17000,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def decode_manufacturer(index, mfg):
 | 
			
		||||
    index &= 0x7f
 | 
			
		||||
    try:
 | 
			
		||||
        return jedec_ids[index][mfg]
 | 
			
		||||
    except (KeyError, IndexError):
 | 
			
		||||
        return 'Unknown ({0}, {1})'.format(index, mfg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def decode_spd_date(year, week):
 | 
			
		||||
    if year == 0 and week == 0:
 | 
			
		||||
        return 'Unknown'
 | 
			
		||||
    return '20{0:02x}-W{1:x}'.format(year, week)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SPD(object):
 | 
			
		||||
    def __init__(self, bytedata):
 | 
			
		||||
        """Parsed memory information
 | 
			
		||||
 | 
			
		||||
        Parse bytedata input and provide a structured detail about the
 | 
			
		||||
        described memory component
 | 
			
		||||
 | 
			
		||||
        :param bytedata: A bytearray of data to decode
 | 
			
		||||
        :return:
 | 
			
		||||
        """
 | 
			
		||||
        self.rawdata = bytearray(bytedata)
 | 
			
		||||
        spd = self.rawdata
 | 
			
		||||
        self.info = {'memory_type': memory_types.get(spd[2], 'Unknown')}
 | 
			
		||||
        if spd[2] == 11:
 | 
			
		||||
            self._decode_ddr3()
 | 
			
		||||
        elif spd[2] == 12:
 | 
			
		||||
            self._decode_ddr4()
 | 
			
		||||
 | 
			
		||||
    def _decode_ddr3(self):
 | 
			
		||||
        spd = self.rawdata
 | 
			
		||||
        finetime = (spd[9] >> 4) / (spd[9] & 0xf)
 | 
			
		||||
        fineoffset = spd[34]
 | 
			
		||||
        if fineoffset & 0b10000000:
 | 
			
		||||
            # Take two's complement for negative offset
 | 
			
		||||
            fineoffset = 0 - ((fineoffset ^ 0xff) + 1)
 | 
			
		||||
        fineoffset = (finetime * fineoffset) * 10**-3
 | 
			
		||||
        mtb = spd[10] / float(spd[11])
 | 
			
		||||
        clock = 2 // ((mtb * spd[12] + fineoffset)*10**-3)
 | 
			
		||||
        self.info['speed'] = speed_by_clock.get(clock, 'Unknown')
 | 
			
		||||
        self.info['ecc'] = (spd[8] & 0b11000) != 0
 | 
			
		||||
        self.info['module_type'] = module_types.get(spd[3] & 0xf, 'Unknown')
 | 
			
		||||
        sdramcap = ddr3_module_capacity[spd[4] & 0xf]
 | 
			
		||||
        buswidth = ddr3_bus_width[spd[8] & 0b111]
 | 
			
		||||
        sdramwidth = ddr3_dev_width[spd[7] & 0b111]
 | 
			
		||||
        ranks = ddr3_ranks[(spd[7] & 0b111000) >> 3]
 | 
			
		||||
        self.info['capacity_mb'] = sdramcap / 8 * buswidth / sdramwidth * ranks
 | 
			
		||||
        self.info['manufacturer'] = decode_manufacturer(spd[117], spd[118])
 | 
			
		||||
        self.info['manufacture_location'] = spd[119]
 | 
			
		||||
        self.info['manufacture_date'] = decode_spd_date(spd[120], spd[121])
 | 
			
		||||
        self.info['model'] = struct.pack('18B', *spd[128:146])
 | 
			
		||||
 | 
			
		||||
    def _decode_ddr4(self):
 | 
			
		||||
        spd = self.rawdata
 | 
			
		||||
        if spd[17] == 0:
 | 
			
		||||
            fineoffset = spd[125]
 | 
			
		||||
            if fineoffset & 0b10000000:
 | 
			
		||||
                fineoffset = 0 - ((fineoffset ^ 0xff) + 1)
 | 
			
		||||
            clock = 2 // ((0.125 * spd[18] + fineoffset * 0.001) * 0.001)
 | 
			
		||||
            self.info['speed'] = speed_by_clock.get(clock, 'Unknown')
 | 
			
		||||
        else:
 | 
			
		||||
            self.info['speed'] = 'Unknown'
 | 
			
		||||
        self.info['ecc'] = (spd[13] & 0b11000) == 0b1000
 | 
			
		||||
        self.info['module_type'] = module_types.get(spd[3] & 0xf,
 | 
			
		||||
                                                    'Unknown')
 | 
			
		||||
        sdramcap = ddr3_module_capacity[spd[4] & 0xf]
 | 
			
		||||
        buswidth = ddr3_bus_width[spd[13] & 0b111]
 | 
			
		||||
        sdramwidth = ddr3_dev_width[spd[12] & 0b111]
 | 
			
		||||
        ranks = ddr3_ranks[(spd[12] & 0b111000) >> 3]
 | 
			
		||||
        self.info['capacity_mb'] = sdramcap / 8 * buswidth / sdramwidth * ranks
 | 
			
		||||
        self.info['manufacturer'] = decode_manufacturer(spd[320], spd[321])
 | 
			
		||||
        self.info['manufacture_location'] = spd[322]
 | 
			
		||||
        self.info['manufacture_date'] = decode_spd_date(spd[323], spd[324])
 | 
			
		||||
        self.info['model'] = struct.pack('18B', *spd[329:347])
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
# coding=utf8
 | 
			
		||||
 | 
			
		||||
# Copyright 2014 IBM Corporation
 | 
			
		||||
# Copyright 2015 Lenovo
 | 
			
		||||
#
 | 
			
		||||
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
# you may not use this file except in compliance with the License.
 | 
			
		||||
@@ -269,9 +270,6 @@ class SDREntry(object):
 | 
			
		||||
            self.sdrtype = TYPE_UNKNOWN   # assume undefined
 | 
			
		||||
            self.oem_decode(entrybytes[5:])
 | 
			
		||||
        elif self.reportunsupported:
 | 
			
		||||
            #will remove once I see it stop being thrown for now
 | 
			
		||||
            #perhaps need some explicit mode to check for
 | 
			
		||||
            #unsupported things, but make do otherwise
 | 
			
		||||
            raise NotImplementedError
 | 
			
		||||
        else:
 | 
			
		||||
            self.sdrtype = TYPE_UNKNOWN
 | 
			
		||||
@@ -301,6 +299,9 @@ class SDREntry(object):
 | 
			
		||||
        self.sdrtype = TYPE_FRU
 | 
			
		||||
        self.fru_name = self.tlv_decode(entry[10], entry[11:])
 | 
			
		||||
        self.fru_number = entry[1]
 | 
			
		||||
        self.fru_logical = (entry[2] & 0b10000000) == 0b10000000
 | 
			
		||||
        # 0x8  to 0x10..  0 unspecified except on 0x10, 1 is dimm
 | 
			
		||||
        self.fru_type_and_modifier = (entry[5] << 8) + entry[6]
 | 
			
		||||
 | 
			
		||||
    def association_decode(self, entry):
 | 
			
		||||
        # table 43-4 Entity Associaition Record
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user