#!/bin/sh
#
# PCI-specific hotplug policy agent.
#
# This should handle 2.4.* PCI (including Cardbus)  hotplugging,
# with a consistent framework for adding device and driver specific
# treatments.
#
# Kernel Cardbus/PCI params are:
#	
#	ACTION=%s [add or remove]
#	PCI_CLASS=%06X
#	PCI_ID=%04X:%04X
#	PCI_SLOT_NAME=%s
#	PCI_SUBSYS_ID=%04X:%04X
#
# If /proc is mounted, /proc/bus/pci/$PCI_SLOT_NAME is almost the name
# of the binary device descriptor file ... just change ':' to '/'.
#
# On systems using Linux 2.4.* kernels, be sure to use the right
# modutils (2.4.1+).
#
#
# HISTORY:
#
# 26-Feb-2001	Cleanup, support comments (Gioele Barabucci)
# 13-Jan-2001	Initial version of "new" hotplug agent; needs
#		retesting.
# 17-Jan-2001	Update to latest kernel syntax (Dan Zink)
# 15-Feb-2001	Remove use of "<<" (Adam Richter)
#
# $Id: pci.agent,v 1.16 2004/09/20 21:43:37 kroah Exp $
#

cd /etc/hotplug
. ./hotplug.functions

# generated by modutils, for current 2.4.x kernels
MAP_CURRENT=$MODULE_DIR/modules.pcimap

# accumulates list of modules we may care about
DRIVERS=

if [ "$PCI_CLASS" = "" ] || [ "$PCI_CLASS" = "" ]; then
    mesg Bad PCI agent invocation
    exit 1
fi

#
# Each modules.usbmap format line corresponds to one entry in a
# MODULE_DEVICE_TABLE(pci,...) declaration in a kernel file.
#
# Think of it as a database column with up to three "match specs"
# to associate kernel modules with particular devices or classes
# of device.  The match specs provide a reasonably good filtering
# mechanism, but some driver probe() routines need to provide
# extra filtering.
#

pci_convert_vars ()
{
    pci_class=$((0x$PCI_CLASS))

    set $(echo $PCI_ID | sed -e 's/\([^:]*\):\(.*\)/\1 \2/')
    pci_id_vendor=$((0x$1))
    pci_id_device=$((0x$2))

    set $(echo $PCI_SUBSYS_ID | sed -e 's/\([^:]*\):\(.*\)/\1 \2/')
    pci_subid_vendor=$((0x$1))
    pci_subid_device=$((0x$2))
}

PCI_ANY=$((0xffffffff))


#
# stdin is "modules.pcimap" syntax
# on return, ONE matching module was added to $DRIVERS
#
pci_map_modules ()
{
    # comment line lists (current) pci_device_id field names
    read ignored

    # look at each pci_device_id entry
    # collect one match in $DRIVERS
    while read module vendor device subvendor subdevice class class_mask ignored
    do
	# comments are lines that start with "#" ...
	# be careful, they still get parsed by bash!
	case "$module" in
	\#*) continue ;;
	esac

	# convert the fields from hex to dec
	vendor=$(($vendor)); device=$(($device))
	subvendor=$(($subvendor)); subdevice=$(($subdevice))
	class=$(($class)); class_mask=$(($class_mask))

	: checkmatch $module

	: vendor $vendor $pci_id_vendor
	if [ $vendor -ne $PCI_ANY ] && [ $vendor -ne $pci_id_vendor ]; then
	    continue
	fi
	: device $device $pci_id_device
	if [ $device -ne $PCI_ANY ] && [ $device -ne $pci_id_device ]; then
	    continue
	fi
	: sub-vendor $subvendor $pci_subid_vendor
	if [ $subvendor -ne $PCI_ANY ] && [ $subvendor -ne $pci_subid_vendor ]; then
	    continue
	fi
	: sub-device $subdevice $pci_subid_device
	if [ $subdevice -ne $PCI_ANY ] && [ $subdevice -ne $pci_subid_device ]; then
	    continue
	fi

	class_temp=$(($pci_class & $class_mask))
	if [ $class_temp -eq $class ]; then
	    DRIVERS="$module $DRIVERS"
	    : drivers $DRIVERS
	    break
	fi
    done
}


#
# What to do with this PCI hotplug event?
#
case $ACTION in

add)
    pci_convert_vars

    LABEL="PCI slot $PCI_SLOT_NAME"

    # on 2.4 systems, modutils maintains MAP_CURRENT
    if [ -r $MAP_CURRENT ]; then
    	load_drivers pci $MAP_CURRENT "$LABEL"
    fi

    if [ "$DRIVERS" = "" ]; then
	debug_mesg "... no modules for $LABEL"
	exit 2
    fi
    ;;

*)
    debug_mesg PCI $ACTION event not supported
    exit 1
    ;;

esac
