mirror of
				https://opendev.org/x/pyghmi
				synced 2025-10-31 11:22:24 +00:00 
			
		
		
		
	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