1616# See the License for the specific language governing permissions and
1717# limitations under the License.
1818
19+ from importlib .resources import files
1920import os
2021import sys
2122import time
2930 sys .exit ("This operating system is not supported." )
3031
3132# To determine what functionality is present
32- I2C_FUNC_I2C = 0x00000001
33+ I2C_FUNC_SMBUS_QUICK = 0x00010000
34+ I2C_FUNC_SMBUS_READ_BYTE = 0x00020000
35+ I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000
36+ I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000
37+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000
38+ I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000
39+ I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000
40+
41+ REQUIRED_FUNC = I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE | \
42+ I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | \
43+ I2C_FUNC_SMBUS_QUICK
3344
3445# Data for SMBus Messages
3546class i2c_smbus_data (ctypes .Union ):
@@ -105,6 +116,10 @@ def print_usage():
105116 print (" -w write data to SPD EEPROM (input from file)" )
106117 print (" -d DIMM DIMM slot index (0 - 7)" )
107118 print (" -f FILE input or output file path" )
119+ print ()
120+ print ("Environment Variables:" )
121+ print (" SPD_EEPROM_SMBUS specify the SMBus index to use (e.g. 1 for /dev/i2c-1)" )
122+ print ()
108123
109124def spd_set_page (fd , page ):
110125 try :
@@ -213,48 +228,75 @@ def smbus_probe(dimm_slot = None):
213228 except Exception :
214229 pass
215230
216- smbus_idx = ""
231+ fd = None
232+ smbus_idx = None
217233
218234 files = os .listdir ("/dev" )
219235 files = list (filter (lambda x : x .startswith ("i2c-" ), files ))
220236
221- for entry in files :
222- fd = os .open ("/dev/" + entry , os .O_RDWR )
223- if not i2c_smbus_get_funcs (fd ) & I2C_FUNC_I2C :
224- smbus_idx = entry [4 :]
225- break
226-
227- if smbus_idx .isdigit ():
228- smbus_idx = int (smbus_idx )
237+ if os .getenv ("SPD_EEPROM_SMBUS" ) is not None :
238+ fd , smbus_idx , n = try_smbus ("i2c-" + os .getenv ("SPD_EEPROM_SMBUS" ), dimm_slot )
239+ if fd is None :
240+ sys .exit ("Could not access SMBus %s." % os .getenv ("SPD_EEPROM_SMBUS" ))
241+ else :
242+ return fd , smbus_idx
229243 else :
230- sys .exit ("No SMBus adapter found." )
231-
232- if dimm_slot == None :
233- print ("Probing for SPD EEPROM on SMBus %d" % smbus_idx )
244+ rets = [try_smbus (x , dimm_slot ) for x in files ]
245+ rets = list (filter (lambda x : x [0 ] is not None , rets ))
246+ rets = sorted (rets , key = lambda x : x [2 ], reverse = True )
247+ if len (rets ) == 0 :
248+ sys .exit ("No supported SMBus found." )
249+ else :
250+ fd , smbus_idx = rets [0 ][0 ], rets [0 ][1 ]
251+ print ("Selecting /dev/i2c-%d by EEPROM count" % smbus_idx )
252+ return fd , smbus_idx
253+
254+
255+ def try_smbus (file : str , dimm_slot = None ):
256+ fd = os .open ("/dev/" + file , os .O_RDWR )
257+ smbus_name : str = file [4 :]
258+ if i2c_smbus_get_funcs (fd ) & REQUIRED_FUNC != REQUIRED_FUNC :
259+ print ("I2C adapter %s does not support required SMBus functions." % file )
234260 print ()
261+ os .close (fd )
262+ return None , None , None
235263
264+ if smbus_name .isdigit ():
265+ smbus_idx : int = int (smbus_name )
266+ else :
267+ print ("Invalid SMBus index: %s" % smbus_name )
268+ return None , None , None
269+
270+ print ("Probing for SPD EEPROM on SMBus %d" % smbus_idx )
271+ if dimm_slot is None :
236272 eeprom = 0
237273 ee1004 = spd_set_page (fd , 0 )
238274
239275 for slot in range (0 , 8 ):
240276 try :
241277 i2c_smbus_read_byte (fd , 0x50 + slot )
242-
243278 print ("DIMM slot %d: %s SPD EEPROM" % (slot , "512 Byte EE1004" if ee1004 else "256 Byte AT24" ))
244-
245279 eeprom += 1
246280 except IOError :
247281 pass
248282
249283 if eeprom == 0 :
250- print ("No SPD EEPROM detected." )
284+ print ("No SPD EEPROM detected on SMBus %d." % smbus_idx )
285+ print ()
286+ os .close (fd )
287+ return None , None , None
251288 else :
252289 try :
253290 i2c_smbus_read_byte (fd , 0x50 + dimm_slot )
291+ eeprom = 1
254292 except IOError :
255- sys .exit ("DIMM slot %d is empty." % dimm_slot )
293+ print ("DIMM slot %d is empty." % dimm_slot )
294+ os .close (fd )
295+ print ()
296+ return None , None , None
256297
257- return fd , smbus_idx
298+ print ()
299+ return fd , smbus_idx , eeprom
258300
259301def main ():
260302 if os .getuid ():
@@ -266,7 +308,7 @@ def main():
266308 sys .exit (print_usage ())
267309
268310 op_code = 0
269- dimm_slot = ""
311+ dimm_slot = None
270312 file_path = ""
271313
272314 for opt , arg in opts :
@@ -282,7 +324,9 @@ def main():
282324 file_path = arg
283325
284326 if op_code == 1 and len (opts ) == 1 :
285- smbus_probe ()
327+ _ , smbus_idx = smbus_probe ()
328+ print ("To save time for next time, you can specify the SMBus index" \
329+ " by: `export SPD_EEPROM_SMBUS=%d`." % smbus_idx )
286330 elif op_code != 0 \
287331 and len (opts ) == 3 \
288332 and len (file_path ) != 0 \
0 commit comments