-#!/bin/sh
+#!/usr/bin/python
-pci_table=/etc/pl_pcitable
+import sys
+import pypciscan
+import pypcimap
+import os
+import time
-echo "pl_hwinit: loading applicable modules"
+loadedmodules = None
-# this will contain lines of device_id:vendor_id (no 0x)
-system_devices=$(lspci -n | cut -d " " -f4)
+def modprobe(module, args = ""):
+ ret = os.system("/sbin/modprobe %s %s" % (module, args))
+ if os.WEXITSTATUS(ret) == 0:
+ globals()['loadedmodules'].write("%s\n" % module)
+ return True
+ else:
+ return False
-for device in $system_devices; do
+def main(argv):
+ if len(argv) == 0:
+ kernel = os.uname()[2]
+ else:
+ kernel = argv[0]
- # now vendor_id and device_id are broken apart
- vendor_id=$(echo $device | cut -d ":" -f1)
- device_id=$(echo $device | cut -d ":" -f2)
+ if os.path.exists(kernel):
+ path = kernel
+ else:
+ path = "/lib/modules/%s/modules.pcimap" % kernel
- # either exactly match vendor:device, or a vendor:ffff (let the module
- # figure out if it can be used for this device), or ffff:device
- # (not sure if this is legal, but shows up in the pci map)
- mods=$(grep -i "\($vendor_id:ffff\|$vendor_id:$device_id\|ffff:$device_id\)" \
- $pci_table | cut -d " " -f1)
+ pcimap = pypcimap.PCIMap(path)
+ print "pl_hwinit: loading applicable modules"
+ devices = pypciscan.get_devices()
+ storage_devices = 0
+ network_devices = 0
+ missing = []
+ globals()['loadedmodules'] = file('/tmp/loadedmodules', 'w')
+ for (slot, dev) in devices.iteritems():
+ modules = pcimap.get(dev)
+ base = (dev[4] & 0xff0000) >> 16
+ if len(modules) == 0:
+ if base == 0x01 or base == 0x02:
+ # storage or network device, in that order
+ missing.append((slot, dev))
+ else:
+ if base == 0x01:
+ storage_devices += 1
+ elif base == 0x02:
+ network_devices += 1
- for module in $mods; do
- if [ -n "$module" ]; then
- echo "pl_hwinit: found and loading module $module"
- /sbin/modprobe $module
- fi
- done
-done
+ # FIXME: This needs improved logic in the case of multiple matching modules
+ for module in modules:
+ print "pl_hwinit: found and loading module %s (%s)" % (module, slot)
+ modprobe(module)
-# just in case, look for any modules that are ffff:ffff and load them
-mods=$(grep -i "ffff:ffff" $pci_table | cut -d " " -f1)
-for module in $mods; do
- if [ -n "$module" ]; then
- echo "pl_hwinit: found and loading wild module $module"
- /sbin/modprobe $module
- fi
-done
+ if network_devices == 0:
+ print "pl_hwinit: no supported network devices found!"
+ print "pl_hwinit: the following devices were found, but have no driver:"
+ print "pl_hwinit: ", "\npl_hwinit: ".join(missing)
-# sd_mod won't get loaded automatically
-echo "pl_hwinit: loading sd_mod"
-/sbin/modprobe sd_mod
+ # XXX: could check for storage devices too, but older kernels have a lot of that built-in
+ # sd_mod won't get loaded automatically
+ print "pl_hwinit: loading sd_mod"
+ modprobe("sd_mod")
+
+ # load usb_storage to support node conf files on flash disks
+ print "pl_hwinit: loading usb_storage"
+ modprobe("usb_storage")
+
+ print "pl_hwinit: loading floppy device driver"
+ modprobe("floppy","floppy=0,allowed_drive_mask")
+
+ # always wait a bit between loading the usb drivers, and checking /sys/
+ # for usb devices (this isn't necessarily for waiting for mass storage files,
+ # that is done below)
+ print "pl_hwinit: waiting for usb system to initialize."
+ time.sleep(10)
+
+ # sometimes, flash devices take a while to initialize. in fact, the kernel
+ # intentionally waits 5 seconds for a device to 'settle'. some take even longer
+ # to show up. if there are any mass storage devices on the system, try to
+ # delay until they come online, up to a max delay of 30s.
+
+ # the way this will be done is to look for files in /sys/devices that are named
+ # 'bInterfaceClass', these will be a list of the usb devices on the system, and
+ # their primary usb device interface class ids. The base directory these files
+ # exist in will be the full path to the /sys/device entry for that device.
+ # for each mass storage devices (they have an interface class value of 08),
+ # we wait for a new symbolic link named 'driver' to exist in that directory,
+ # indicating the kernel loaded a driver for that device.
+
+ # usb interface class id for mass storage
+ INTERFACE_CLASS_MASS_STORAGE = "08"
+
+ # how long to wait in seconds before continuing on if devices
+ # aren't available
+ MAX_USB_WAIT_TIME = 30
+
+ # low long in seconds to wait between checks
+ PER_CHECK_USB_WAIT_TIME = 5
+
+
+ # find out if the device identified by the /sys dir has a module
+ # loaded for it. check for a symlink in the dir named driver.
+ def does_device_dir_have_driver(device):
+ return os.path.exists(os.path.join(device, "driver"))
+
+ def filter_and_add(list, directory, files):
+ if ("bInterfaceClass" in files and
+ int(file(os.path.join(directory, "bInterfaceClass")).read(), 16) == INTERFACE_CLASS_MASS_STORAGE):
+ list.append(directory)
+
+ wait_dev_list = []
+ os.path.walk("/sys/devices", filter_and_add, wait_dev_list)
+
+ if len(wait_dev_list) > 0:
+ print "pl_hwinit: found USB mass storage device(s). Attempting to wait"
+ print "pl_hwinit: up to %d seconds for them to come online." % MAX_USB_WAIT_TIME
+
+ total_wait_time = 0
+ success = False
+ while total_wait_time < MAX_USB_WAIT_TIME:
+ total_wait_time += PER_CHECK_USB_WAIT_TIME
+
+ print "pl_hwinit: waiting %d seconds." % PER_CHECK_USB_WAIT_TIME
+ time.sleep(PER_CHECK_USB_WAIT_TIME)
+
+ all_devices_online = True
+ for device in wait_dev_list:
+ if not does_device_dir_have_driver(device):
+ all_devices_online = False
+
+ if all_devices_online:
+ success = True
+ print "pl_hwinit: looks like the devices are now online."
+ break
+ else:
+ print "pl_hwinit: not all devices online yet, waiting..."
+
+ if success:
+ print "pl_hwinit: Succesfully waited for USB mass storage devices"
+ print "pl_hwinit: to come online."
+ else:
+ print "pl_hwinit: One or more USB mass storage devices did not"
+ print "pl_hwinit: initialize in time. Continuing anyway."
+
+if __name__ == "__main__":
+ main(sys.argv[1:])