Cyril Olivier MARTIN wrote:

Tu as mis-à-jour que hotplug ? pas le noyau ?
Cela donne l'impression que le coldplug fonctionne mais pas l'hotplug (hotplug restart c'est comme au boot).

sous RH9 je me suis contenté d'installer hotplug (version du 29/03/2004), sous Mdk10 & FC2, je n'ai rien fait de spécial (hotplug y était déjà, je ne sais pas sous quelle version)

Est-ce que tout le monde a les mêmes scripts d'hotplug ? Ou bien sont-ils écrits pour chaque distribution ? Dans le second cas il doit exister une norme ou une tentative de normalisation au moins:-) et j'aimerais bien lire usb.rc et usb.agent pour comparer avec les miens.

j'ai bien l'impression que non puisque les tailles sont légèrement différentes... je t'ai mis les 2 scripts pour chaque distrib, dans l'ordre RH9, Mdk10, FC2.
bonne lecture !

JM.

#!/bin/sh
# vim: syntax=sh
#
# usb.rc        This brings the USB subsystem up and down safely.
#
# $Id: usb.rc,v 1.22 2004/03/27 07:44:39 ukai Exp $
#
# Best invoked via /etc/init.d/hotplug or equivalent, with
# writable /tmp, /usr mounted, and syslogging active.
#
# Bus management is basically unrelated to runlevel changes; it
# relates to physical topology, including possibly hotpluggable
# busses (USB, Cardbus) or controllers.  If a bus is physically
# present, it should normally be available.
# 
# USB-dependant systems (iMacs, "legacy free" x86 systems, and so on)
# should statically link USB keyboard support into the kernel (USB core,
# EHCI/OHCI/UHCI/..., hid, input, keybdev; and likely mousedev) so the
# system console can't be removed by accident.


PATH=/sbin:/bin:/usr/sbin:/usr/bin

unset I_WANT_A_BROKEN_PS
PS_PERSONALITY=linux

STATIC_MODULE_LIST=
X11_USBMICE_HACK=false

# override any of the defaults above?
if [ -f /etc/sysconfig/usb ]; then
    . /etc/sysconfig/usb
fi


MOUSE_MODULES="mousedev input"

# In its currently-recommended configuration, XFree86 3.3.6 always opens
# /dev/input/mice; so mousedev and input must be loaded before X11 starts.
if [ $X11_USBMICE_HACK = true ]; then
    STATIC_MODULE_LIST="$MOUSE_MODULES $STATIC_MODULE_LIST"
fi


#
# "COLD PLUG" ... recovery from partial USB init that may have happened
# before the OS could really handle hotplug, perhaps because /sbin or
# $HOTPLUG_DIR wasn't available or /tmp wasn't writable.  When/if the
# /sbin/hotplug program is invoked then, hotplug event notifications
# get dropped.  To make up for such "cold boot" errors, we synthesize
# all the hotplug events we expect to have seen already.  They can be
# out of order, and some might be duplicates.
#
# Note that on 2.5 the init filesystem may have loaded some of the more
# essential usb drivers (maybe usb-storage for a boot disk, and hid),
# but we may still need to load less important ones or invoke setup
# scripts that couldn't run earlier.
#
usb_boot_events ()
{
        #
        # FIXME on 2.5, /sys/bus/usb/devices/* gives all of the
        # info we need.  Interface hotplug events come from the
        # "*:*" files, and device events (do them first) come
        # from the others. 
        #
        # don't expect usbmodules to exist!!  and remove the
        # dependency (below) on usbfs to decide whether we should
        # be synthesizing coldplug events.
        #

        # synthesize hotplug events if we can 
        # we need (non-bash) programs to parse descriptors.
        LISTER=`which usbmodules`
        if [ "$LISTER" = "" -o ! -f /proc/bus/usb/devices ]; then
                echo $"** can't synthesize root hub events"
                return
        fi

        # make sure the usb agent will run
        ACTION=add
        PRODUCT=0/0/0
        TYPE=
        INTERFACE=
        DEVPATH=
        DEVFS=/proc/bus/usb
        DEVICE=
        export ACTION PRODUCT TYPE INTERFACE DEVPATH DEVFS DEVICE

        # these notifications will be handled by usbmodules
        # NOTE: we're not providing a full set of hotplug
        # parameters for USB.  that's why "usbmodules" is a
        # requirement: it reads usbfs to get the others.
        # (it's included in usbutils 0.8 and later)
        #
        # FIXME usbmodules, or something, should set real
        # PRODUCT and DEVICE strings so /etc/hotplug/usb/*
        # scripts can rely on them ...
        # FIXME: this comment is out of date.
        if [ -d /sys/bus ]; then
            if [ -d /sys/bus/usb/devices ]; then
                cd /sys/bus/usb/devices
                # XXX FIXME this is not the right way...
                for device in /sys/bus/usb/devices/[0-9]*; do
                    DEVPATH=${device#/sys/}
                    if [ -f $device/idVendor ]; then
                         PRODUCT="$(cat $device/idVendor)/$(cat 
$device/idProduct)/$(cat $device/bcdDevice)"
                         /etc/hotplug/usb.agent
                    fi  
                done
            fi
        else
            for DEVICE in /proc/bus/usb/*/*; do
                /etc/hotplug/usb.agent
            done
        fi
}


maybe_start_usb ()
{
    local COUNT SYNTHESIZE
    COUNT=0

    # if USB is partially initted then synthesize "cold plug" events. the
    # kernel probably dropped many "hot plug" events, and those it didn't
    # drop likely couldn't trigger all the setup actions (kicking daemons,
    # dropping config records, and so on).

    # if it's not initted at all (no hcds loaded) no synthesized events
    # will be needed, we'll see real ones.  knowing that there are no
    # hcds available through version-portable logic is a nightmare, so
    # assume we synthesize unless "usbfs" is clearly not initted (which
    # we currently need when synthesizing, anyway).

    SYNTHESIZE=true
    if [ ! -d /proc/bus/usb ]; then
        SYNTHESIZE=false
    fi

    # if distro hasn't already done part of this ... load core,
    # and mount usbfs before the first hotplug agent fires
    # (so it'll be available to the agents).
    modprobe -q usbcore >/dev/null 2>&1
    if [ -d /proc/bus/usb ]; then
        # if it's not mounted, try to mount it
        if [ ! -f /proc/bus/usb/devices ]; then
            if grep -q -E 
"^[^#][^[:space:]]+[[:space:]]+/proc/bus/usb/?[[:space:]]" /etc/fstab; then
                mount /proc/bus/usb
            else
                if grep -q usbfs /proc/filesystems; then
                    mount -t usbfs usbfs /proc/bus/usb
                else
                    mount -t usbdevfs usbdevfs /proc/bus/usb
                fi
            fi
        fi
    fi

    # Load Host Controller Drivers (HCDs) ... this automatically handles
    # systems with multiple controllers (EHCI, OHCI, UHCI) without needing
    # /proc or tools (lspci -v|grep USB, etc) to do so.  If hotplugging
    # is enabled on this system, initting a root hub will cause hotplug
    # events to fire for every device on the tree at that root.

    # FIXME: some of this should be driven by PCI hotplugging, and have
    # the blacklist control which uhci driver gets used (before 2.5).

    # "new style" HCDs ... more common code
    modprobe -q ehci-hcd >/dev/null 2>&1
    modprobe -q ohci-hcd >/dev/null 2>&1
    modprobe -q uhci-hcd >/dev/null 2>&1

    # "old style" HCDs ... more driver-specific bugs
    modprobe -q usb-ohci >/dev/null 2>&1
    # NOTE: this prefers "uhci"; you may prefer "usb-uhci".
    # modprobe -q usb-uhci >/dev/null 2>&1 || modprobe -q uhci >/dev/null 2>&1
    modprobe -q uhci >/dev/null 2>&1 || modprobe -q usb-uhci >/dev/null 2>&1

    # ... add any non-PCI HCDS here.  Examples include the
    # CRIS usb-host, Philips ISP-1161, Symlogic 811HS, and so on.
    # ohci-hcd can handle some non-pci variants.

    if [ -d /proc/bus/usb ]; then
        # If we see there are no busses, we "failed" and
        # can report so even if we're partially nonmodular.
        #
        # NOTE: this fails on older kernels, where usbdevfs had two files
        # ('devices' and 'drivers') with no hcds registered, but works on
        # newer kernels where usbfs has zero files until hcds register,
        # and might not have the 'drivers' file.
        COUNT=`ls /proc/bus/usb | wc -l`
        if [ $COUNT -lt 2 ]; then
            umount /proc/bus/usb
            rmmod usbcore >/dev/null 2>&1
            return 1
        fi

    # if USB is fully modular and yet can clean up,
    # we know init failed without needing usbfs
    elif rmmod usbcore >/dev/null 2>&1; then
        return 1
    fi

    # hotplug events didn't fire during booting;
    # cope with devices that enumerated earlier
    # and may not have been fully configured.
    if [ $SYNTHESIZE = true ]; then
        sleep 1
        usb_boot_events
    fi

    # Some modules are statically loaded, perhaps because they are
    # needed to activate filesystem device nodes.
    for MODULE in $STATIC_MODULE_LIST; do
        modprobe $MODULE
    done

    # we did everything we could ...
    return 0
}

maybe_stop_usb ()
{
    # call this multiple times if you had to take down components of the
    # USB subsystem by hand; it cleans up whatever can
    # be cleaned up, letting the system quiesce further.

    # NOTE:  this list of "all USB modules" is unfortunate, but it seems
    # inevitable until modutils supports the notion of drivers with use
    # counts of zero that shouldn't be removed until after their device
    # gets removed.  Maybe in 2.5 ... of necessity, the list is partial.

    # disconnect all controllers we can, and kernel drivers
    # HCDs first, so most drivers reduce their use counts.
    rmmod ehci-hcd >/dev/null 2>&1
    rmmod ohci-hcd >/dev/null 2>&1
    rmmod uhci-hcd >/dev/null 2>&1
    rmmod usb-ohci >/dev/null 2>&1
    rmmod usb-uhci >/dev/null 2>&1
    rmmod     uhci >/dev/null 2>&1

    # user mode code may keep usbfs busy for a while yet ...

    # OK, usbcore won't actually be removed unless there happen to be
    # no USB drivers loaded, and usbfs isn't mounted.  let's force
    # removal of autocleanable modules before trying to rmmod usbcore
    rmmod -as
# note: module-init-tools 0.8a doesn't handle "-as" flags

    # Now let's workaround the fact that some USB modules never increase
    # their module use counts, so that "rmmod -a" won't unload them.
    # (And we can't use "modprobe --autoclean" anyway.)
    rmmod acm              >/dev/null 2>&1
    rmmod audio            >/dev/null 2>&1
    rmmod auerswald        >/dev/null 2>&1
    rmmod belkin_sa        >/dev/null 2>&1
    rmmod bluetooth        >/dev/null 2>&1
    rmmod catc             >/dev/null 2>&1
    rmmod CDCEther         >/dev/null 2>&1
    rmmod cpia_usb         >/dev/null 2>&1
    rmmod cyberjack        >/dev/null 2>&1
    rmmod dabusb           >/dev/null 2>&1
    rmmod dc2xx            >/dev/null 2>&1
    rmmod digi_acceleport  >/dev/null 2>&1
    rmmod dsbr100          >/dev/null 2>&1
    rmmod emi26            >/dev/null 2>&1
    rmmod empeg            >/dev/null 2>&1
    rmmod ftdi_sio         >/dev/null 2>&1
    rmmod hci_usb          >/dev/null 2>&1
    rmmod hid              >/dev/null 2>&1
    rmmod hpusbscsi        >/dev/null 2>&1
    rmmod ibmcam           >/dev/null 2>&1
    rmmod iforce           >/dev/null 2>&1
    rmmod io_edgeport      >/dev/null 2>&1
    rmmod ipaq             >/dev/null 2>&1
    rmmod ir-usb           >/dev/null 2>&1
    rmmod irda-usb         >/dev/null 2>&1
    rmmod kaweth           >/dev/null 2>&1
    rmmod keyspan          >/dev/null 2>&1
    rmmod keyspan_pda      >/dev/null 2>&1
    rmmod kl5kusb105       >/dev/null 2>&1
    rmmod mct_u232         >/dev/null 2>&1
    rmmod mdc800           >/dev/null 2>&1
    rmmod microtek         >/dev/null 2>&1
    rmmod omninet          >/dev/null 2>&1
    rmmod ov511            >/dev/null 2>&1
    rmmod pegasus          >/dev/null 2>&1
    rmmod pl2303           >/dev/null 2>&1
    rmmod printer          >/dev/null 2>&1
    rmmod pwc pwcx         >/dev/null 2>&1
    rmmod rio500           >/dev/null 2>&1
    rmmod rtl8150          >/dev/null 2>&1
    rmmod scanner          >/dev/null 2>&1
    rmmod se401            >/dev/null 2>&1
    rmmod stv680           >/dev/null 2>&1
    rmmod usbkbd           >/dev/null 2>&1
    rmmod usbmouse         >/dev/null 2>&1
    rmmod usbnet           >/dev/null 2>&1
    rmmod usbtest          >/dev/null 2>&1
    rmmod usb-storage      >/dev/null 2>&1
    rmmod uss720           >/dev/null 2>&1
    rmmod vicam            >/dev/null 2>&1
    rmmod visor            >/dev/null 2>&1
    rmmod wacom            >/dev/null 2>&1
    rmmod whiteheat        >/dev/null 2>&1

    if [ "$STATIC_MODULE_LIST" != "" ]; then
        rmmod $STATIC_MODULE_LIST >/dev/null 2>&1
    fi

    # remove the helper modules that some usb modules need
    rmmod usbserial        >/dev/null 2>&1
    rmmod usbvideo         >/dev/null 2>&1

    # ok, hope that user mode drivers/managers closed their fds.
    umount /proc/bus/usb >/dev/null 2>&1

    rmmod usbcore >/dev/null 2>&1

    # we did everything we could ...
    return 0;
}

# See how we were called.
case "$1" in
  start)
        maybe_start_usb
        ;;
  stop)
        maybe_stop_usb
        ;;
  status)
        echo $"USB Status for kernel: " `uname -srm`
        echo ''

        if [ -f /proc/bus/usb/devices ]; then
            # as noted above:  this fails on older kernels,
            # where usbfs created files differently.
            COUNT=`ls /proc/bus/usb | wc -l`
            if [ $COUNT -ge 2 ]; then
                COUNT=`expr $COUNT - 2`
                echo $"USB up; bus count is $COUNT"
                grep "^[TPSI]:" /proc/bus/usb/devices
            else
                echo $"usbfs partially up; no busses"
            fi
            echo ''

            echo $"USB Drivers Loaded: "
            if [ -f /proc/bus/usb/drivers ]; then
                cat /proc/bus/usb/drivers
            fi
            if [ -d /sys/bus/usb ]; then
                ls -1 /sys/bus/usb/drivers
            fi
        else
            echo $"usbfs is unavailable. "
            if [ -f /proc/modules ] && fgrep -q usbcore /proc/modules; then
                echo $"USB module is loaded. "
            else
                echo $"USB may be statically linked. "
            fi
            echo $"If khubd is running, that shows USB is available."
        fi
        echo ''

        if [ -f /proc/sys/kernel/hotplug ]; then
            echo $"khubd/hotplug thread: "
        else
            echo $"khubd thread:"
        fi
        ps -l | head -1
        ps -Al | egrep 'khubd' | grep -v grep
        echo ''

        lsmod
        echo ''

        # /proc/devices too? "usb", "input", and others ...

        ;;
  restart)
        # always invoke by absolute path, else PATH=$PATH:
        $0 stop && $0 start
        ;;
  *)
        echo $"Usage: $0 {start|stop|status|restart}"
        exit 1
esac
#!/bin/sh
#
# USB-specific hotplug policy agent.
#
# This should handle 2.2.18+, 2.4.*, and 2.5.* USB hotplugging,
# with a consistent framework for adding device and driver
# specific handling.
#
# Normally, adding a usb device will modprobe a driver.  If there
# is a /etc/hotplug/usb/$DRIVER script set up, it will also run,
# handling tasks like loading firmware or starting daemons.
#
# Kernel USB hotplug params include:
#       
#       ACTION=%s [add or remove]
#       DEVPATH=%s [in 2.5 kernels, /sys/$DEVPATH]
#       PRODUCT=%x/%x/%x
#       INTERFACE=%d/%d/%d [ for interface 0, if TYPE=0/*/* ]
#       TYPE=%d/%d/%d
#
# And if usbfs (originally called usbdevfs) is configured, also:
#
#       DEVFS=/proc/bus/usb [gone in 2.5]
#       DEVICE=/proc/bus/usb/%03d/%03d
#
# This script then adds the variable:
#
#       REMOVER=/var/run/usb/<some string unique to $DEVICE>
#
# This is the path where the script would like to find a remover, if
# the target device needs one. This script is executed on remove if
# it is executable when the remove happens.
#
# If usbfs is mounted on /proc/bus/usb, $DEVICE is a file which
# can be read to get the device's current configuration descriptor.
# (The "usbmodules" utility does that.)  Or it can be used by a
# user mode driver to interact with the usb device.  USB hotplug
# does *not* require usbfs (or sysfs) to work, although on 2.4
# some devices work better if "usbmodules" can help.
#
# For Linux 2.5+ kernels, there's no need for "usbmodules".  For
# two reasons:  first, hotplug is invoked for each interface, not
# just the first one.  Second, sysfs exposes descriptors so they
# are easy to use for "coldplug" event simulation.  (But sysfs is
# not a replacement for the driver I/O capabilities in usbfs.)
#
# On systems using Linux 2.4.* kernels, be sure to use the right
# modutils (2.4.2+).  That ensures that hotplugging uses the list
# of modules installed for your kernel, rather than the one that's
# included here for use on systems without MODULE_DEVICE_TABLE
# support.
#
#
# HISTORY:
#
# 20-Nov-2002   some 2.5 updates; handle new 'device' hotplug; turn off
#               'sleep' hack since hcds must all queue control traffic
# 08-Aug-2002   support for multiple usermaps (maxk), minor cleanup
# 18-Jan-2002   fix match algorithm in usb_map_modules()
# 14-Jan-2002   fix work around 2.2 brokeness of $PRODUCT
# 09-Jan-2002   REMOVER for system without usbdevfs
#
# 14-Mar-2001   Cleanup, bitmask the match_flags
# 26-Feb-2001   Cleanup, support comments (Gioele Barabucci)
# 15-Feb-2001   Remove use of "<<" (Adam Richter)
# 23-Jan-2001   Update 2.2 handling; unfortunately there's no "feature
#               test" that can work robustly
# 05-Jan-2001   Quick hack for kernel 2.4.0 and modutils 2.4.1
# 03-Jan-2001   Initial version of "new" hotplug agent, using feedback
#               and contributions from Adam Richter, Ryan VanderBijl,
#               Norbert Preining, Florian Lohoff, David Brownell and
#               others.  To replace the original /etc/usb/policy. (db)
#
# $Id: usb.agent,v 1.39 2004/03/26 22:36:38 kroah Exp $
#

if [ -f /etc/sysconfig/usb ]; then
    . /etc/sysconfig/usb
fi

cd /etc/hotplug
. ./hotplug.functions
# DEBUG=yes export DEBUG

# generated by modutils, for current 2.4.x (and later) kernels
MAP_CURRENT=$MODULE_DIR/modules.usbmap

# used if MAP_CURRENT is missing; for 2.2.x kernels
MAP_DISTMAP=$HOTPLUG_DIR/usb.distmap

#
# used for kernel drivers that don't show up in CURRENT or DISTMAP,
# currently input drivers (joysticks, keyboards, etc).  newer systems
# should use input hotplug events instead.
#
MAP_HANDMAP=$HOTPLUG_DIR/usb.handmap

#
# used to run config scripts for user mode drivers (jPhoto, gPhoto2,
# rio500 tools, etc) ... instead of naming kernel modules, it names
# config scripts.  those could change $DEVICE permissions, etc.
#
# for purely user mode drivers, scripts $HOTPLUG_DIR/usb/NAME should be
# installed with usermap files in $HOTPLUG_DIR/usb/NAME.usermap instead
# of continuing to use/modify $MAP_USERMAP 
#
MAP_USERMAP=$HOTPLUG_DIR/usb.usermap


# accumulates list of modules we may care about
DRIVERS=""

if [ "$ACTION" = "" ]; then
    mesg Bad USB agent invocation, no action
    exit 1
fi

# starting in kernel 2.5 there are two kinds of USB hotplug events.
# - per-interface; 2.2/2.4 kernels only reported the first one.
#       "new" events have nonzero /sys/$DEVPATH/bInterfaceNumber
# - per-device; "new" events don't have $PRODUCT
SYSFS=/sys
if [ "$PRODUCT" = "" ]; then
    # this is either an error, or we're on a 2.5 system...
    if [ "$DEVPATH" = "" ]; then
        mesg Bad USB agent invocation
        exit 1
    fi

    # sysfs files may already be gone
    if [ $ACTION = 'remove' ]; then
        exit 0
    fi

    # we could be running before usb populated these attributes...
    if [ ! -f $SYSFS/$DEVPATH/bNumConfigurations ]; then
        # FIXME wait till they appear, or N seconds elapse
        sleep 2
    fi

    # this could care about changing the default config, or warning
    # when the user hooked a fast device up so it runs slowly.
    if [ ! -f $SYSFS/$DEVPATH/bNumConfigurations ]; then
        exit 0
    fi
    TMP=$(cat $SYSFS/$DEVPATH/bNumConfigurations)
    if [ $TMP -ne 1 -a "$ACTION" = add ]; then
        mesg Keeping default configuration with $SYSFS/$DEVPATH
    fi

    # NOTE:  it might be good to add an extension hook here rather
    # than ignore these events, but even device-scope tasks such
    # as firmware download can still use the interface-0 event
    # (as they did with 2.2/2.4 hotplug setup scripts).
    exit 0
fi

# we can't "unset IFS" on bash1, so save a copy
DEFAULT_IFS="$IFS"

#
# Each modules.usbmap format line corresponds to one entry in a
# MODULE_DEVICE_TABLE(usb,...) 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.
#

usb_convert_vars ()
{
    # work around 2.2.early brokenness
    # munges the usb_bcdDevice such that it is a integer rather
    # than a float: e.g. 1.0 become 0100
    PRODUCT=`echo $PRODUCT | sed -e "s+\.\([0-9]\)$+.\10+" -e "s/\.$/00/" \
                                  -e "s+/\([0-9]\)\.\([0-9][0-9]\)+/0\1\2+" \
                          -e "s+/\([0-9][0-9]\)\.\([0-9][0-9]\)+/\1\2+"`
    set $(echo $PRODUCT | sed -e 's+\([^/]*\)/\([^/]*\)/\(.*\)+\1 \2 \3+')
    usb_idVendor=$((0x$1))
    usb_idProduct=$((0x$2))
    usb_bcdDevice=$((0x$3))

    if [ "$TYPE" != "" ]; then
        IFS=/
        set $TYPE ''
        usb_bDeviceClass=$1
        usb_bDeviceSubClass=$2
        usb_bDeviceProtocol=$3
        IFS="$DEFAULT_IFS"
    elif [ -r $SYSFS/$DEVPATH/bDeviceClass ]; then
        usb_bDeviceClass=$((0x$(cat $SYSFS/$DEVPATH/bDeviceClass)))
        usb_bDeviceSubClass=$((0x$(cat $SYSFS/$DEVPATH/bDeviceSubClass)))
        usb_bDeviceProtocol=$((0x$(cat $SYSFS/$DEVPATH/bDeviceProtocol)))
    else
        # out-of-range values
        usb_bDeviceClass=1000
        usb_bDeviceSubClass=1000
        usb_bDeviceProtocol=1000
    fi

    if [ "$INTERFACE" != "" ]; then
        IFS=/
        set $INTERFACE ''
        usb_bInterfaceClass=$1
        usb_bInterfaceSubClass=$2
        usb_bInterfaceProtocol=$3
        IFS="$DEFAULT_IFS"
    elif [ -r $SYSFS/$DEVPATH/bInterfaceClass ]; then
        usb_bInterfaceClass=$((0x$(cat $SYSFS/$DEVPATH/bInterfaceClass)))
        usb_bInterfaceSubClass=$((0x$(cat $SYSFS/$DEVPATH/bInterfaceSubClass)))
        usb_bInterfaceProtocol=$((0x$(cat $SYSFS/$DEVPATH/bInterfaceProtocol)))
    else
        # out-of-range values
        usb_bInterfaceClass=1000
        usb_bInterfaceSubClass=1000
        usb_bInterfaceProtocol=1000
    fi
}

USB_MATCH_VENDOR=$((0x0001))
USB_MATCH_PRODUCT=$((0x0002))
USB_MATCH_DEV_LO=$((0x0004))
USB_MATCH_DEV_HI=$((0x0008))
USB_MATCH_DEV_CLASS=$((0x0010))
USB_MATCH_DEV_SUBCLASS=$((0x0020))
USB_MATCH_DEV_PROTOCOL=$((0x0040))
USB_MATCH_INT_CLASS=$((0x0080))
USB_MATCH_INT_SUBCLASS=$((0x0100))
USB_MATCH_INT_PROTOCOL=$((0x0200))

#
# stdin is "modules.usbmap" syntax
# on return, all matching modules were added to $DRIVERS
#
usb_map_modules ()
{
    local line module

    # look at each usb_device_id entry
    # collect all matches in $DRIVERS

    while read line
    do
        # comments are lines that start with "#" ...
        # be careful, they still get parsed by bash!
        case "$line" in
        \#*) continue ;;
        esac

        set $line

        module=$1
        match_flags=$(($2))

        idVendor=$(($3))
        idProduct=$(($4))
        bcdDevice_lo=$(($5))
        bcdDevice_hi=$(($6))

        bDeviceClass=$(($7))
        bDeviceSubClass=$(($8))
        bDeviceProtocol=$(($9))

        shift 9
        bInterfaceClass=$(($1))
        bInterfaceSubClass=$(($2))
        bInterfaceProtocol=$(($3))

        : checkmatch $module

        : idVendor $idVendor $usb_idVendor
        if [ $USB_MATCH_VENDOR -eq $(( $match_flags & $USB_MATCH_VENDOR )) ] && 
           [ $idVendor -ne $usb_idVendor ]; then
            continue
        fi

        : idProduct $idProduct $usb_idProduct
        if [ $USB_MATCH_PRODUCT -eq $(( $match_flags & $USB_MATCH_PRODUCT )) ] 
&&
           [ $idProduct -ne $usb_idProduct ]; then
            continue
        fi

        : bcdDevice range $bcdDevice_hi $bcdDevice_lo actual $usb_bcdDevice
        if [ $USB_MATCH_DEV_LO -eq $(( $match_flags & $USB_MATCH_DEV_LO )) ] &&
           [ $usb_bcdDevice -lt $bcdDevice_lo ]; then
            continue
        fi

        # bcdDevice_lo <= bcdDevice <= bcdDevice_hi
        if [ $USB_MATCH_DEV_HI -eq $(( $match_flags & $USB_MATCH_DEV_HI )) ] &&
           [ $usb_bcdDevice -gt $bcdDevice_hi ]; then
            continue
        fi

        : bDeviceClass $bDeviceClass $usb_bDeviceClass
        if [ $USB_MATCH_DEV_CLASS -eq $(( $match_flags & $USB_MATCH_DEV_CLASS 
)) ] &&
           [ $bDeviceClass -ne $usb_bDeviceClass ]; then
            continue
        fi
        : bDeviceSubClass $bDeviceSubClass $usb_bDeviceSubClass
        if [ $USB_MATCH_DEV_SUBCLASS -eq $(( $match_flags & 
$USB_MATCH_DEV_SUBCLASS )) ] &&
           [ $bDeviceSubClass -ne $usb_bDeviceSubClass ]; then
            continue
        fi
        : bDeviceProtocol $bDeviceProtocol $usb_bDeviceProtocol
        if [ $USB_MATCH_DEV_PROTOCOL -eq $(( $match_flags & 
$USB_MATCH_DEV_PROTOCOL )) ] &&
           [ $bDeviceProtocol -ne $usb_bDeviceProtocol ]; then
            continue
        fi

        # NOTE:  for now, this only checks the first of perhaps
        # several interfaces for this device.

        : bInterfaceClass $bInterfaceClass $usb_bInterfaceClass
        if [ $USB_MATCH_INT_CLASS -eq $(( $match_flags & $USB_MATCH_INT_CLASS 
)) ] &&
           [ $bInterfaceClass -ne $usb_bInterfaceClass ]; then
            continue
        fi
        : bInterfaceSubClass $bInterfaceSubClass $usb_bInterfaceSubClass
        if [ $USB_MATCH_INT_SUBCLASS -eq $(( $match_flags & 
$USB_MATCH_INT_SUBCLASS )) ] &&
           [ $bInterfaceSubClass -ne $usb_bInterfaceSubClass ]; then
            continue
        fi
        : bInterfaceProtocol $bInterfaceProtocol $usb_bInterfaceProtocol
        if [ $USB_MATCH_INT_PROTOCOL -eq $(( $match_flags & 
$USB_MATCH_INT_PROTOCOL )) ] &&
           [ $bInterfaceProtocol -ne $usb_bInterfaceProtocol ]; then
            continue
        fi

        # It was a match!
        DRIVERS="$module $DRIVERS"
        : drivers $DRIVERS
    done
}

#
# declare a REMOVER name that the add action can use to create a
# remover, or that the remove action can use to execute a remover.
#
if [ "$DEVICE" = "" ]; then
  REMOVER=/var/run/usb/`echo "$INTERFACE/$PRODUCT/$TYPE" | sed -e 's;/;%;g'`
else
  REMOVER=/var/run/usb/`echo $DEVICE | sed -e 's;/;%;g'`
fi
export REMOVER

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

add)
    # partial workaround for 2.4 uhci/usb-uhci driver problem:  they don't
    # queue control requests, so device drivers can confuse each other if
    # they happen to issue requests at the same time ... it happens easily
    # with slow HID devices and "usbmodules".
    # starting with 2.5 (DEVPATH set), all hcds must queue control traffic.
    if [ "$DEVPATH" = "" ]; then
        sleep 3
    fi

    usb_convert_vars

    FOUND=false
    if [ -f $SYSFS/$DEVPATH/manufacturer ]; then
        LABEL="USB `cat $SYSFS/$DEVPATH/manufacturer` `cat 
$SYSFS/$DEVPATH/product`"
    else
        LABEL="USB product $PRODUCT"
    fi

    if [ -e "$REMOVER" ]; then
        rm -f "$REMOVER"
    fi

    # on 2.4 systems, modutils 2.4.2+ maintains MAP_CURRENT
    # ... otherwise we can't rely on it (sigh)
    case "$KERNEL" in
    2.4.*|2.5.*|2.6.*)
        if [ -r $MAP_CURRENT ]; then
            load_drivers usb $MAP_CURRENT "$LABEL"
        fi;;
    *)
        if [ -r $MAP_DISTMAP ]; then
            load_drivers usb $MAP_DISTMAP "$LABEL"
        fi;;
    esac
    if [ "$DRIVERS" != "" ]; then
        FOUND=true
    fi

    # cope with special driver module configurations
    # (mostly HID devices, until we have an input.agent)
    # not needed on 2.6 - they are loaded by hotplug
    case "$KERNEL" in
        2.6.* )
            : nothing
        ;;
        * )
            if [ -r $MAP_HANDMAP ]; then
                load_drivers usb $MAP_HANDMAP "$LABEL"
                if [ "$DRIVERS" != "" ]; then
                    FOUND=true
                fi
            fi
        ;;
    esac

    # some devices have user-mode drivers (no kernel module, but config)
    # or specialized user-mode setup helpers 
    MODPROBE=:
    for MAP in $MAP_USERMAP $HOTPLUG_DIR/usb/*.usermap
    do
        if [ -r $MAP ]; then
            load_drivers usb $MAP "$LABEL"
            if [ "$DRIVERS" != "" ]; then
                FOUND=true
            fi
        fi
    done

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

remove)
    if [ -x $REMOVER ]; then
        $REMOVER
    fi
    rm -f $REMOVER

    if [ -x /usr/sbin/updfstab ]; then
        /usr/sbin/updfstab
    fi
    ;;

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

esac
#!/bin/sh
# vim: syntax=sh
#
# usb.rc        This brings the USB subsystem up and down safely.
#
# $Id: usb.rc,v 1.19 2003/09/25 00:09:08 kroah Exp $
#
# Best invoked via /etc/init.d/hotplug or equivalent, with
# writable /tmp, /usr mounted, and syslogging active.
#
# Bus management is basically unrelated to runlevel changes; it
# relates to physical topology, including possibly hotpluggable
# busses (USB, Cardbus) or controllers.  If a bus is physically
# present, it should normally be available.
# 
# USB-dependant systems (iMacs, "legacy free" x86 systems, and so on)
# should statically link USB keyboard support into the kernel (USB core,
# EHCI/OHCI/UHCI/..., hid, input, keybdev; and likely mousedev) so the
# system console can't be removed by accident.


PATH=/sbin:/bin:/usr/sbin:/usr/bin

STATIC_MODULE_LIST=
X11_USBMICE_HACK=false

# source function library
if [ -f /etc/init.d/functions ]; then
        . /etc/init.d/functions
elif [ -f /etc/rc.d/init.d/functions ]; then
        . /etc/rc.d/init.d/functions
fi


# override any of the defaults above?
if [ -f /etc/sysconfig/usb ]; then
    . /etc/sysconfig/usb
fi

grep -iq nousb /proc/cmdline && exit 0
if [ "$USB" = "no" ];then
    exit 0
fi

function mount_proc_usb () {
    local usbfs

    # prefer usbfs on 2.5
    if grep -q usbfs /proc/filesystems; then
        usbfs=usbfs
    elif grep -q usbdevfs  /proc/filesystems;then
        usbfs=usbdevfs
    fi

    if [[ -n "$usbfs" ]] && ! grep -q /proc/bus/usb /proc/mounts;then
        mount -t $usbfs -o devmode=0664,devgid=43 none /proc/bus/usb
    fi
}

MOUSE_MODULES="mousedev input"

# In its currently-recommended configuration, XFree86 3.3.6 always opens
# /dev/input/mice; so mousedev and input must be loaded before X11 starts.
if [ $X11_USBMICE_HACK = true ]; then
    STATIC_MODULE_LIST="$MOUSE_MODULES $STATIC_MODULE_LIST"
fi


#
# "COLD PLUG" ... recovery from partial USB init that may have happened
# before the OS could really handle hotplug, perhaps because /sbin or
# $HOTPLUG_DIR wasn't available or /tmp wasn't writable.  When/if the
# /sbin/hotplug program is invoked then, hotplug event notifications
# get dropped.  To make up for such "cold boot" errors, we synthesize
# all the hotplug events we expect to have seen already.  They can be
# out of order, and some might be duplicates.
#
# Note that on 2.5 the init filesystem may have loaded some of the more
# essential usb drivers (maybe usb-storage for a boot disk, and hid),
# but we may still need to load less important ones or invoke setup
# scripts that couldn't run earlier.
#
usb_boot_events ()
{
        #
        # FIXME on 2.5, /sys/bus/usb/devices/* gives all of the
        # info we need.  Interface hotplug events come from the
        # "*:*" files, and device events (do them first) come
        # from the others. 
        #
        # don't expect usbmodules to exist!!  and remove the
        # dependency (below) on usbfs to decide whether we should
        # be synthesizing coldplug events.
        #

        # synthesize hotplug events if we can 
        # we need (non-bash) programs to parse descriptors.
        LISTER=`type -p usbmodules`
        if [ "$LISTER" = "" -o ! -f /proc/bus/usb/devices ]; then
                echo $"** can't synthesize root hub events"
                return
        fi

        # make sure the usb agent will run
        ACTION=add
        PRODUCT=0/0/0
        export ACTION PRODUCT

        DEVFS=/proc/bus/usb
        DEVICE=
        export DEVFS DEVICE

        DEVPATH=
        export DEVPATH

        # these notifications will be handled by usbmodules
        # NOTE: we're not providing a full set of hotplug
        # parameters for USB.  that's why "usbmodules" is a
        # requirement: it reads usbfs to get the others.
        # (it's included in usbutils 0.8 and later)
        #
        # FIXME usbmodules, or something, should set real
        # PRODUCT and DEVICE strings so /etc/hotplug/usb/*
        # scripts can rely on them ...
        #
        # for 2.6 lister is disabled so either this should be fixed
        # or we just use sysfs
        if [ -d /sys/bus/usb/devices ]; then
            declare device
            for device in /sys/bus/usb/devices/*; do
                DEVPATH=${device#/sys/}
                /etc/hotplug/usb.agent
            done
        else
            for DEVICE in /proc/bus/usb/*/*
            do
                    /etc/hotplug/usb.agent
            done
        fi
}


maybe_start_usb ()
{
    local COUNT SYNTHESIZE
    COUNT=0

    # if USB is partially initted then synthesize "cold plug" events. the
    # kernel probably dropped many "hot plug" events, and those it didn't
    # drop likely couldn't trigger all the setup actions (kicking daemons,
    # dropping config records, and so on).

    # if it's not initted at all (no hcds loaded) no synthesized events
    # will be needed, we'll see real ones.  knowing that there are no
    # hcds available through version-portable logic is a nightmare, so
    # assume we synthesize unless "usbfs" is clearly not initted (which
    # we currently need when synthesizing, anyway).

    SYNTHESIZE=true
    if [ ! -d /proc/bus/usb ]; then
        SYNTHESIZE=false
    fi

    # if distro hasn't already done part of this ... load core,
    # and mount usbfs before the first hotplug agent fires
    # (so it'll be available to the agents).
    modprobe -q usbcore >/dev/null 2>&1
    if [ -d /proc/bus/usb ]; then
        # if it's not mounted, try to mount it
        if [ ! -f /proc/bus/usb/devices ]; then
            if grep -q "[        ]/proc/bus/usb[         ]" /etc/fstab ; then
                mount /proc/bus/usb
            else
                # NOTE: name is changing to "usbfs" from "usbdevfs"
                # NOTE: some versions don't create empty 'devices' files
                mount_proc_usb
            fi
        fi
    fi

    # Load Host Controller Drivers (HCDs) ... this automatically handles
    # systems with multiple controllers (EHCI, OHCI, UHCI) without needing
    # /proc or tools (lspci -v|grep USB, etc) to do so.  If hotplugging
    # is enabled on this system, initting a root hub will cause hotplug
    # events to fire for every device on the tree at that root.

    # FIXME: some of this should be driven by PCI hotplugging, and have
    # the blacklist control which uhci driver gets used (before 2.5).

    modprobe -q usb-interface

####     # "new style" HCDs ... more common code
####     modprobe -q ehci-hcd >/dev/null 2>&1
####     modprobe -q ohci-hcd >/dev/null 2>&1
####     modprobe -q uhci-hcd >/dev/null 2>&1
#### 
####     # "old style" HCDs ... more driver-specific bugs
####     modprobe -q usb-ohci >/dev/null 2>&1
####     # NOTE: this prefers "uhci"; you may prefer "usb-uhci".
####     # modprobe -q usb-uhci >/dev/null 2>&1 || modprobe -q uhci >/dev/null 
2>&1
####     modprobe -q uhci >/dev/null 2>&1 || modprobe -q usb-uhci >/dev/null 
2>&1
#### 
####     # ... add any non-PCI HCDS here.  Examples include the
####     # CRIS usb-host, Philips ISP-1161, Symlogic 811HS, and so on.
####     # ohci-hcd can handle some non-pci variants.

    if [ -d /proc/bus/usb ]; then
        # If we see there are no busses, we "failed" and
        # can report so even if we're partially nonmodular.
        #
        # NOTE: this fails on older kernels, where usbdevfs had two files
        # ('devices' and 'drivers') with no hcds registered, but works on
        # newer kernels where usbfs has zero files until hcds register,
        # and might not have the 'drivers' file.
        COUNT=`ls /proc/bus/usb | wc -l`
        if [ $COUNT -lt 2 ]; then
            umount /proc/bus/usb
            rmmod usbcore >/dev/null 2>&1
            return 1
        fi

    # if USB is fully modular and yet can clean up,
    # we know init failed without needing usbfs
    elif rmmod usbcore >/dev/null 2>&1; then
        return 1
    fi

    # hotplug events didn't fire during booting;
    # cope with devices that enumerated earlier
    # and may not have been fully configured.
    if [ $SYNTHESIZE = true ]; then
        usb_boot_events
    fi

    # Some modules are statically loaded, perhaps because they are
    # needed to activate filesystem device nodes.
    for MODULE in $STATIC_MODULE_LIST; do
        modprobe $MODULE
    done

    # we did everything we could ...
    return 0
}

maybe_stop_usb ()
{
    # call this multiple times if you had to take down components of the
    # USB subsystem by hand; it cleans up whatever can
    # be cleaned up, letting the system quiesce further.

    # NOTE:  this list of "all USB modules" is unfortunate, but it seems
    # inevitable until modutils supports the notion of drivers with use
    # counts of zero that shouldn't be removed until after their device
    # gets removed.  Maybe in 2.5 ... of necessity, the list is partial.

    # disconnect all controllers we can, and kernel drivers
    # HCDs first, so most drivers reduce their use counts.
    rmmod ehci-hcd >/dev/null 2>&1
    rmmod ohci-hcd >/dev/null 2>&1
    rmmod uhci-hcd >/dev/null 2>&1
    rmmod usb-ohci >/dev/null 2>&1
    rmmod usb-uhci >/dev/null 2>&1
    rmmod     uhci >/dev/null 2>&1

    # user mode code may keep usbfs busy for a while yet ...

    # OK, usbcore won't actually be removed unless there happen to be
    # no USB drivers loaded, and usbfs isn't mounted.  let's force
    # removal of autocleanable modules before trying to rmmod usbcore
    rmmod -as
# note: module-init-tools 0.8a doesn't handle "-as" flags

    # Now let's workaround the fact that some USB modules never increase
    # their module use counts, so that "rmmod -a" won't unload them.
    # (And we can't use "modprobe --autoclean" anyway.)
    rmmod acm              >/dev/null 2>&1
    rmmod audio            >/dev/null 2>&1
    rmmod auerswald        >/dev/null 2>&1
    rmmod belkin_sa        >/dev/null 2>&1
    rmmod bluetooth        >/dev/null 2>&1
    rmmod catc             >/dev/null 2>&1
    rmmod CDCEther         >/dev/null 2>&1
    rmmod cpia_usb         >/dev/null 2>&1
    rmmod cyberjack        >/dev/null 2>&1
    rmmod dabusb           >/dev/null 2>&1
    rmmod dc2xx            >/dev/null 2>&1
    rmmod digi_acceleport  >/dev/null 2>&1
    rmmod dsbr100          >/dev/null 2>&1
    rmmod emi26            >/dev/null 2>&1
    rmmod empeg            >/dev/null 2>&1
    rmmod ftdi_sio         >/dev/null 2>&1
    rmmod hci_usb          >/dev/null 2>&1
    rmmod hid              >/dev/null 2>&1
    rmmod hpusbscsi        >/dev/null 2>&1
    rmmod ibmcam           >/dev/null 2>&1
    rmmod iforce           >/dev/null 2>&1
    rmmod io_edgeport      >/dev/null 2>&1
    rmmod ipaq             >/dev/null 2>&1
    rmmod ir-usb           >/dev/null 2>&1
    rmmod irda-usb         >/dev/null 2>&1
    rmmod kaweth           >/dev/null 2>&1
    rmmod keyspan          >/dev/null 2>&1
    rmmod keyspan_pda      >/dev/null 2>&1
    rmmod kl5kusb105       >/dev/null 2>&1
    rmmod mct_u232         >/dev/null 2>&1
    rmmod mdc800           >/dev/null 2>&1
    rmmod microtek         >/dev/null 2>&1
    rmmod omninet          >/dev/null 2>&1
    rmmod ov511            >/dev/null 2>&1
    rmmod pegasus          >/dev/null 2>&1
    rmmod pl2303           >/dev/null 2>&1
    rmmod printer          >/dev/null 2>&1
    rmmod pwc pwcx         >/dev/null 2>&1
    rmmod rio500           >/dev/null 2>&1
    rmmod rtl8150          >/dev/null 2>&1
    rmmod scanner          >/dev/null 2>&1
    rmmod se401            >/dev/null 2>&1
    rmmod stv680           >/dev/null 2>&1
    rmmod usbkbd           >/dev/null 2>&1
    rmmod usblp            >/dev/null 2>&1
    rmmod usbmouse         >/dev/null 2>&1
    rmmod usbnet           >/dev/null 2>&1
    rmmod usbtest          >/dev/null 2>&1
    rmmod usb-storage      >/dev/null 2>&1
    rmmod uss720           >/dev/null 2>&1
    rmmod vicam            >/dev/null 2>&1
    rmmod visor            >/dev/null 2>&1
    rmmod wacom            >/dev/null 2>&1
    rmmod whiteheat        >/dev/null 2>&1

    if [ "$STATIC_MODULE_LIST" != "" ]; then
        rmmod $STATIC_MODULE_LIST >/dev/null 2>&1
    fi

    # remove the helper modules that some usb modules need
    rmmod usbserial        >/dev/null 2>&1
    rmmod usbvideo         >/dev/null 2>&1

    # ok, hope that user mode drivers/managers closed their fds.
    umount /proc/bus/usb >/dev/null 2>&1

    rmmod usbcore >/dev/null 2>&1

    # we did everything we could ...
    return 0;
}

# See how we were called.
case "$1" in
  start)
        maybe_start_usb
        ;;
  stop)
        maybe_stop_usb
        ;;
  status)
        echo $"USB Status for kernel: " `uname -srm`
        echo ''

        if [ -f /proc/bus/usb/devices ]; then
            # as noted above:  this fails on older kernels,
            # where usbfs created files differently.
            COUNT=`ls /proc/bus/usb | wc -l`
            if [ $COUNT -ge 2 ]; then
                COUNT=`expr $COUNT - 2`
                echo $"USB up; bus count is $COUNT"
                grep "^[TPSI]:" /proc/bus/usb/devices
            else
                echo $"usbfs partially up; no busses"
            fi
            echo ''

            echo $"USB Drivers Loaded: "
            if [ -f /proc/bus/usb/drivers ]; then
                cat /proc/bus/usb/drivers
            fi
            if [ -d /sys/bus/usb ]; then
                ls -1 /sys/bus/usb/drivers
            fi
        else
            echo $"usbfs is unavailable. "
            if [ -f /proc/modules ] && fgrep -q usbcore /proc/modules; then
                echo $"USB module is loaded. "
            else
                echo $"USB may be statically linked. "
            fi
            echo $"If khubd is running, that shows USB is available."
        fi
        echo ''

        if [ -f /proc/sys/kernel/hotplug ]; then
            echo $"khubd/hotplug thread: "
        else
            echo $"khubd thread:"
        fi
        ps -l | head -1
        ps -Al | egrep 'khubd' | grep -v grep
        echo ''

        lsmod
        echo ''

        # /proc/devices too? "usb", "input", and others ...

        ;;
  restart)
        # always invoke by absolute path, else PATH=$PATH:
        $0 stop && $0 start
        ;;
  *)
        echo $"Usage: $0 {start|stop|status|restart}"
        exit 1
esac
#!/bin/bash
#
# USB-specific hotplug policy agent.
#
# This should handle 2.2.18+, 2.4.*, and 2.5.* USB hotplugging,
# with a consistent framework for adding device and driver
# specific handling.
#
# Normally, adding a usb device will modprobe a driver.  If there
# is a /etc/hotplug/usb/$DRIVER script set up, it will also run,
# handling tasks like loading firmware or starting daemons.
#
# Kernel USB hotplug params include:
#       
#       ACTION=%s [add or remove]
#       DEVPATH=%s [in 2.5 kernels, /sys/$DEVPATH]
#       PRODUCT=%x/%x/%x
#       INTERFACE=%d/%d/%d [ for interface 0, if TYPE=0/*/* ]
#       TYPE=%d/%d/%d
#
# And if usbfs (originally called usbdevfs) is configured, also:
#
#       DEVFS=/proc/bus/usb [gone in 2.5]
#       DEVICE=/proc/bus/usb/%03d/%03d
#
# This script then adds the variable:
#
#       REMOVER=/var/run/usb/<some string unique to $DEVICE>
#
# This is the path where the script would like to find a remover, if
# the target device needs one. This script is executed on remove if
# it is executable when the remove happens.
#
# If usbfs is mounted on /proc/bus/usb, $DEVICE is a file which
# can be read to get the device's current configuration descriptor.
# (The "usbmodules" utility does that.)  Or it can be used by a
# user mode driver to interact with the usb device.  USB hotplug
# does *not* require usbfs (or sysfs) to work, although on 2.4
# some devices work better if "usbmodules" can help.
#
# For Linux 2.5+ kernels, there's no need for "usbmodules".  For
# two reasons:  first, hotplug is invoked for each interface, not
# just the first one.  Second, sysfs exposes descriptors so they
# are easy to use for "coldplug" event simulation.  (But sysfs is
# not a replacement for the driver I/O capabilities in usbfs.)
#
# On systems using Linux 2.4.* kernels, be sure to use the right
# modutils (2.4.2+).  That ensures that hotplugging uses the list
# of modules installed for your kernel, rather than the one that's
# included here for use on systems without MODULE_DEVICE_TABLE
# support.
#
#
# HISTORY:
#
# 20-Nov-2002   some 2.5 updates; handle new 'device' hotplug; turn off
#               'sleep' hack since hcds must all queue control traffic
# 08-Aug-2002   support for multiple usermaps (maxk), minor cleanup
# 18-Jan-2002   fix match algorithm in usb_map_modules()
# 14-Jan-2002   fix work around 2.2 brokeness of $PRODUCT
# 09-Jan-2002   REMOVER for system without usbdevfs
#
# 14-Mar-2001   Cleanup, bitmask the match_flags
# 26-Feb-2001   Cleanup, support comments (Gioele Barabucci)
# 15-Feb-2001   Remove use of "<<" (Adam Richter)
# 23-Jan-2001   Update 2.2 handling; unfortunately there's no "feature
#               test" that can work robustly
# 05-Jan-2001   Quick hack for kernel 2.4.0 and modutils 2.4.1
# 03-Jan-2001   Initial version of "new" hotplug agent, using feedback
#               and contributions from Adam Richter, Ryan VanderBijl,
#               Norbert Preining, Florian Lohoff, David Brownell and
#               others.  To replace the original /etc/usb/policy. (db)
#
# $Id: usb.agent,v 1.35 2003/10/13 23:52:54 kroah Exp $
#

if [ -f /etc/sysconfig/usb ]; then
    . /etc/sysconfig/usb
fi

cd /etc/hotplug
. hotplug.functions
# DEBUG=yes export DEBUG

# generated by modutils, for current 2.4.x (and later) kernels
MAP_CURRENT=$MODULE_DIR/modules.usbmap

# used if MAP_CURRENT is missing; for 2.2.x kernels
MAP_DISTMAP=$HOTPLUG_DIR/usb.distmap

#
# used for kernel drivers that don't show up in CURRENT or DISTMAP,
# currently input drivers (joysticks, keyboards, etc).  newer systems
# should use input hotplug events instead.
#
MAP_HANDMAP=$HOTPLUG_DIR/usb.handmap

#
# used to run config scripts for user mode drivers (jPhoto, gPhoto2,
# rio500 tools, etc) ... instead of naming kernel modules, it names
# config scripts.  those could change $DEVICE permissions, etc.
#
# for purely user mode drivers, scripts $HOTPLUG_DIR/usb/NAME should be
# installed with usermap files in $HOTPLUG_DIR/usb/NAME.usermap instead
# of continuing to use/modify $MAP_USERMAP 
#
MAP_USERMAP=$HOTPLUG_DIR/usb.usermap


# accumulates list of modules we may care about
DRIVERS=""

if [ "$ACTION" = "" ]; then
    mesg Bad USB agent invocation, no action
    exit 1
fi

# starting in kernel 2.5 there are two kinds of USB hotplug events.
# - per-interface; 2.2/2.4 kernels only reported the first one.
#       "new" events have nonzero /sys/$DEVPATH/bInterfaceNumber
# - per-device; "new" events don't have $PRODUCT
SYSFS=/sys
if [ "$PRODUCT" = "" ]; then
    # this is either an error, or we're on a 2.5 system...
    if [ "$DEVPATH" = "" ]; then
        mesg Bad USB agent invocation
        exit 1
    fi

    # sysfs files may already be gone
    if [ $ACTION = 'remove' ]; then
        exit 0
    fi

    # we could be running before usb populated these attributes...
    if [ ! -f $SYSFS/$DEVPATH/bNumConfigurations ]; then
        # FIXME wait till they appear, or N seconds elapse
        sleep 2
    fi

    # this could care about changing the default config, or warning
    # when the user hooked a fast device up so it runs slowly.
    TMP=$(cat $SYSFS/$DEVPATH/bNumConfigurations)
    if [ $TMP -ne 1 -a "$ACTION" = add ]; then
        mesg Keeping default configuration with $SYSFS/$DEVPATH
    fi

    # NOTE:  it might be good to add an extension hook here rather
    # than ignore these events, but even device-scope tasks such
    # as firmware download can still use the interface-0 event
    # (as they did with 2.2/2.4 hotplug setup scripts).
    exit 0
fi

# we can't "unset IFS" on bash1, so save a copy
DEFAULT_IFS="$IFS"

#
# Each modules.usbmap format line corresponds to one entry in a
# MODULE_DEVICE_TABLE(usb,...) 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.
#
declare -i usb_idVendor usb_idProduct usb_bcdDevice
declare -i usb_bDeviceClass usb_bDeviceSubClass usb_bDeviceProtocol
declare -i usb_bInterfaceClass usb_bInterfaceSubClass usb_bInterfaceProtocol

usb_convert_vars ()
{
    if [ "$AWK" = "" ]; then
        mesg "can't find awk!"
        exit 1
    fi

    # work around 2.2.early brokenness
    # munges the usb_bcdDevice such that it is a integer rather
    # than a float: e.g. 1.0 become 0100
    PRODUCT=`echo $PRODUCT | sed -e "s+\.\([0-9]\)$+.\10+" -e "s/\.$/00/" \
                                  -e "s+/\([0-9]\)\.\([0-9][0-9]\)+/0\1\2+" \
                          -e "s+/\([0-9][0-9]\)\.\([0-9][0-9]\)+/\1\2+"`
    set `echo $PRODUCT | $AWK -F/ '{print "0x" $1, "0x" $2, "0x" $3 }'` ''
    usb_idVendor=$1
    usb_idProduct=$2
    usb_bcdDevice=$3

    if [ "$TYPE" != "" ]; then
        IFS=/
        set $TYPE ''
        usb_bDeviceClass=$1
        usb_bDeviceSubClass=$2
        usb_bDeviceProtocol=$3
        IFS="$DEFAULT_IFS"
    elif [ -r $SYSFS/$DEVPATH/bDeviceClass ]; then
        usb_bDeviceClass=0x$(cat $SYSFS/$DEVPATH/bDeviceClass)
        usb_bDeviceSubClass=0x$(cat $SYSFS/$DEVPATH/bDeviceSubClass)
        usb_bDeviceProtocol=0x$(cat $SYSFS/$DEVPATH/bDeviceProtocol)
    else
        # out-of-range values
        usb_bDeviceClass=1000
        usb_bDeviceSubClass=1000
        usb_bDeviceProtocol=1000
    fi

    if [ "$INTERFACE" != "" ]; then
        IFS=/
        set $INTERFACE ''
        usb_bInterfaceClass=$1
        usb_bInterfaceSubClass=$2
        usb_bInterfaceProtocol=$3
        IFS="$DEFAULT_IFS"
    elif [ -r $SYSFS/$DEVPATH/bInterfaceClass ]; then
        usb_bInterfaceClass=0x$(cat $SYSFS/$DEVPATH/bInterfaceClass)
        usb_bInterfaceSubClass=0x$(cat $SYSFS/$DEVPATH/bInterfaceSubClass)
        usb_bInterfaceProtocol=0x$(cat $SYSFS/$DEVPATH/bInterfaceProtocol)
    else
        # out-of-range values
        usb_bInterfaceClass=1000
        usb_bInterfaceSubClass=1000
        usb_bInterfaceProtocol=1000
    fi
}

declare -i USB_MATCH_VENDOR=0x0001
declare -i USB_MATCH_PRODUCT=0x0002
declare -i USB_MATCH_DEV_LO=0x0004
declare -i USB_MATCH_DEV_HI=0x0008
declare -i USB_MATCH_DEV_CLASS=0x0010
declare -i USB_MATCH_DEV_SUBCLASS=0x0020
declare -i USB_MATCH_DEV_PROTOCOL=0x0040
declare -i USB_MATCH_INT_CLASS=0x0080
declare -i USB_MATCH_INT_SUBCLASS=0x0100
declare -i USB_MATCH_INT_PROTOCOL=0x0200

#
# stdin is "modules.usbmap" syntax
# on return, all matching modules were added to $DRIVERS
#
usb_map_modules ()
{
    # convert the usb_device_id fields to integers as we read them 
    local line module
    declare -i match_flags
    declare -i idVendor idProduct bcdDevice_lo bcdDevice_hi
    declare -i bDeviceClass bDeviceSubClass bDeviceProtocol
    declare -i bInterfaceClass bInterfaceSubClass bInterfaceProtocol

    # look at each usb_device_id entry
    # collect all matches in $DRIVERS

    while read line
    do
        # comments are lines that start with "#" ...
        # be careful, they still get parsed by bash!
        case "$line" in
        \#*) continue ;;
        esac

        set $line

        module=$1
        match_flags=$2

        idVendor=$3
        idProduct=$4
        bcdDevice_lo=$5
        bcdDevice_hi=$6

        bDeviceClass=$7
        bDeviceSubClass=$8
        bDeviceProtocol=$9

        shift 9
        bInterfaceClass=$1
        bInterfaceSubClass=$2
        bInterfaceProtocol=$3

        : checkmatch $module

        : idVendor $idVendor $usb_idVendor
        if [ $USB_MATCH_VENDOR -eq $(( $match_flags & $USB_MATCH_VENDOR )) ] && 
           [ $idVendor -ne $usb_idVendor ]; then
            continue
        fi

        : idProduct $idProduct $usb_idProduct
        if [ $USB_MATCH_PRODUCT -eq $(( $match_flags & $USB_MATCH_PRODUCT )) ] 
&&
           [ $idProduct -ne $usb_idProduct ]; then
            continue
        fi

        : bcdDevice range $bcdDevice_hi $bcdDevice_lo actual $usb_bcdDevice
        if [ $USB_MATCH_DEV_LO -eq $(( $match_flags & $USB_MATCH_DEV_LO )) ] &&
           [ $usb_bcdDevice -lt $bcdDevice_lo ]; then
            continue
        fi

        # bcdDevice_lo <= bcdDevice <= bcdDevice_hi
        if [ $USB_MATCH_DEV_HI -eq $(( $match_flags & $USB_MATCH_DEV_HI )) ] &&
           [ $usb_bcdDevice -gt $bcdDevice_hi ]; then
            continue
        fi

        : bDeviceClass $bDeviceClass $usb_bDeviceClass
        if [ $USB_MATCH_DEV_CLASS -eq $(( $match_flags & $USB_MATCH_DEV_CLASS 
)) ] &&
           [ $bDeviceClass -ne $usb_bDeviceClass ]; then
            continue
        fi
        : bDeviceSubClass $bDeviceSubClass $usb_bDeviceSubClass
        if [ $USB_MATCH_DEV_SUBCLASS -eq $(( $match_flags & 
$USB_MATCH_DEV_SUBCLASS )) ] &&
           [ $bDeviceSubClass -ne $usb_bDeviceSubClass ]; then
            continue
        fi
        : bDeviceProtocol $bDeviceProtocol $usb_bDeviceProtocol
        if [ $USB_MATCH_DEV_PROTOCOL -eq $(( $match_flags & 
$USB_MATCH_DEV_PROTOCOL )) ] &&
           [ $bDeviceProtocol -ne $usb_bDeviceProtocol ]; then
            continue
        fi

        # NOTE:  for now, this only checks the first of perhaps
        # several interfaces for this device.

        : bInterfaceClass $bInterfaceClass $usb_bInterfaceClass
        if [ $USB_MATCH_INT_CLASS -eq $(( $match_flags & $USB_MATCH_INT_CLASS 
)) ] &&
           [ $bInterfaceClass -ne $usb_bInterfaceClass ]; then
            continue
        fi
        : bInterfaceSubClass $bInterfaceSubClass $usb_bInterfaceSubClass
        if [ $USB_MATCH_INT_SUBCLASS -eq $(( $match_flags & 
$USB_MATCH_INT_SUBCLASS )) ] &&
           [ $bInterfaceSubClass -ne $usb_bInterfaceSubClass ]; then
            continue
        fi
        : bInterfaceProtocol $bInterfaceProtocol $usb_bInterfaceProtocol
        if [ $USB_MATCH_INT_PROTOCOL -eq $(( $match_flags & 
$USB_MATCH_INT_PROTOCOL )) ] &&
           [ $bInterfaceProtocol -ne $usb_bInterfaceProtocol ]; then
            continue
        fi

        # It was a match!
        DRIVERS="$module $DRIVERS"
        : drivers $DRIVERS
    done
}

#
# declare a REMOVER name that the add action can use to create a
# remover, or that the remove action can use to execute a remover.
#
if [ "$DEVICE" = "" ]; then
  declare -rx REMOVER=/var/run/usb/`echo "$INTERFACE/$PRODUCT/$TYPE" | sed -e 
's;/;%;g'`
else
  declare -rx REMOVER=/var/run/usb/`echo $DEVICE | sed -e 's;/;%;g'`
fi

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

add)
    # partial workaround for 2.4 uhci/usb-uhci driver problem:  they don't
    # queue control requests, so device drivers can confuse each other if
    # they happen to issue requests at the same time ... it happens easily
    # with slow HID devices and "usbmodules".
    # starting with 2.5 (DEVPATH set), all hcds must queue control traffic.
    if [ "$DEVPATH" = "" ]; then
        sleep 3
    fi

    usb_convert_vars

    FOUND=false
    LABEL="USB product $PRODUCT"

    if [ -e "$REMOVER" ]; then
        rm -f "$REMOVER"
    fi

    # on 2.4 systems, modutils 2.4.2+ maintains MAP_CURRENT
    # ... otherwise we can't rely on it (sigh)
    case "$KERNEL" in
    2.4.*|2.5.*|2.6.*)
        if [ -r $MAP_CURRENT ]; then
            load_drivers usb $MAP_CURRENT "$LABEL"
        fi;;
    *)
        if [ -r $MAP_DISTMAP ]; then
            load_drivers usb $MAP_DISTMAP "$LABEL"
        fi;;
    esac
    if [ "$DRIVERS" != "" ]; then
        FOUND=true
    fi

    # cope with special driver module configurations
    # (mostly HID devices, until we have an input.agent)
    # not needed on 2.6 - they are loaded by hotplug
    case "$KERNEL" in
        2.6.* )
            : nothing
        ;;
        * )
            if [ -r $MAP_HANDMAP ]; then
                load_drivers usb $MAP_HANDMAP "$LABEL"
                if [ "$DRIVERS" != "" ]; then
                    FOUND=true
                fi
            fi
        ;;
    esac

    # some devices have user-mode drivers (no kernel module, but config)
    # or specialized user-mode setup helpers 
    MODPROBE=:
    for MAP in $MAP_USERMAP $HOTPLUG_DIR/usb/*.usermap
    do
        if [ -r $MAP ]; then
            load_drivers usb $MAP "$LABEL"
            if [ "$DRIVERS" != "" ]; then
                FOUND=true
            fi
        fi
    done

    if [ "$FOUND" = "false" ]; then
        mesg "... no modules for $LABEL"
        exit 2
    fi
    ;;

remove)
    if [ -x $REMOVER ]; then
        $REMOVER
    fi
    rm -f $REMOVER

    if [ -x /usr/sbin/updfstab ]; then
        /usr/sbin/updfstab
    fi
    ;;

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

esac
#!/bin/sh
# vim: syntax=sh
#
# usb.rc        This brings the USB subsystem up and down safely.
#
# $Id: usb.rc,v 1.23 2004/04/01 07:27:47 kroah Exp $
#
# Best invoked via /etc/init.d/hotplug or equivalent, with
# writable /tmp, /usr mounted, and syslogging active.
#
# Bus management is basically unrelated to runlevel changes; it
# relates to physical topology, including possibly hotpluggable
# busses (USB, Cardbus) or controllers.  If a bus is physically
# present, it should normally be available.
# 
# USB-dependant systems (iMacs, "legacy free" x86 systems, and so on)
# should statically link USB keyboard support into the kernel (USB core,
# EHCI/OHCI/UHCI/..., hid, input, keybdev; and likely mousedev) so the
# system console can't be removed by accident.


PATH=/sbin:/bin:/usr/sbin:/usr/bin

unset I_WANT_A_BROKEN_PS
PS_PERSONALITY=linux

STATIC_MODULE_LIST=
X11_USBMICE_HACK=false

# override any of the defaults above?
if [ -f /etc/sysconfig/usb ]; then
    . /etc/sysconfig/usb
fi
if [ -f /etc/conf.d/usb ]; then
    . /etc/conf.d/usb
fi


MOUSE_MODULES="mousedev input"

# In its currently-recommended configuration, XFree86 3.3.6 always opens
# /dev/input/mice; so mousedev and input must be loaded before X11 starts.
if [ $X11_USBMICE_HACK = true ]; then
    STATIC_MODULE_LIST="$MOUSE_MODULES $STATIC_MODULE_LIST"
fi


#
# "COLD PLUG" ... recovery from partial USB init that may have happened
# before the OS could really handle hotplug, perhaps because /sbin or
# $HOTPLUG_DIR wasn't available or /tmp wasn't writable.  When/if the
# /sbin/hotplug program is invoked then, hotplug event notifications
# get dropped.  To make up for such "cold boot" errors, we synthesize
# all the hotplug events we expect to have seen already.  They can be
# out of order, and some might be duplicates.
#
# Note that on 2.5 the init filesystem may have loaded some of the more
# essential usb drivers (maybe usb-storage for a boot disk, and hid),
# but we may still need to load less important ones or invoke setup
# scripts that couldn't run earlier.
#
usb_boot_events ()
{
        #
        # FIXME on 2.5, /sys/bus/usb/devices/* gives all of the
        # info we need.  Interface hotplug events come from the
        # "*:*" files, and device events (do them first) come
        # from the others. 
        #
        # don't expect usbmodules to exist!!  and remove the
        # dependency (below) on usbfs to decide whether we should
        # be synthesizing coldplug events.
        #

        # synthesize hotplug events if we can 
        # we need (non-bash) programs to parse descriptors.
        LISTER=`which usbmodules`
        if [ "$LISTER" = "" -o ! -f /proc/bus/usb/devices ]; then
                echo $"** can't synthesize root hub events"
                return
        fi

        # make sure the usb agent will run
        ACTION=add
        PRODUCT=0/0/0
        TYPE=
        INTERFACE=
        DEVPATH=
        DEVFS=/proc/bus/usb
        DEVICE=
        export ACTION PRODUCT TYPE INTERFACE DEVPATH DEVFS DEVICE

        # these notifications will be handled by usbmodules
        # NOTE: we're not providing a full set of hotplug
        # parameters for USB.  that's why "usbmodules" is a
        # requirement: it reads usbfs to get the others.
        # (it's included in usbutils 0.8 and later)
        #
        # FIXME usbmodules, or something, should set real
        # PRODUCT and DEVICE strings so /etc/hotplug/usb/*
        # scripts can rely on them ...
        # FIXME: this comment is out of date.
        if [ -d /sys/bus ]; then
            if [ -d /sys/bus/usb/devices ]; then
                cd /sys/bus/usb/devices
                # XXX FIXME this is not the right way...
                for device in /sys/bus/usb/devices/[0-9]*; do
                    DEVPATH=${device#/sys/}
                    if [ -f $device/idVendor ]; then
                         PRODUCT="$(cat $device/idVendor)/$(cat 
$device/idProduct)/$(cat $device/bcdDevice)"
                         /etc/hotplug/usb.agent
                    fi  
                done
            fi
        else
            for DEVICE in /proc/bus/usb/*/*; do
                /etc/hotplug/usb.agent
            done
        fi
}


maybe_start_usb ()
{
    local COUNT SYNTHESIZE
    COUNT=0

    # if USB is partially initted then synthesize "cold plug" events. the
    # kernel probably dropped many "hot plug" events, and those it didn't
    # drop likely couldn't trigger all the setup actions (kicking daemons,
    # dropping config records, and so on).

    # if it's not initted at all (no hcds loaded) no synthesized events
    # will be needed, we'll see real ones.  knowing that there are no
    # hcds available through version-portable logic is a nightmare, so
    # assume we synthesize unless "usbfs" is clearly not initted (which
    # we currently need when synthesizing, anyway).

    SYNTHESIZE=true
    if [ ! -d /proc/bus/usb ]; then
        SYNTHESIZE=false
    fi

    # if distro hasn't already done part of this ... load core,
    # and mount usbfs before the first hotplug agent fires
    # (so it'll be available to the agents).
    modprobe -q usbcore >/dev/null 2>&1
    if [ -d /proc/bus/usb ]; then
        # if it's not mounted, try to mount it
        if [ ! -f /proc/bus/usb/devices ]; then
            if grep -q -E 
"^[^#][^[:space:]]+[[:space:]]+/proc/bus/usb/?[[:space:]]" /etc/fstab; then
                mount /proc/bus/usb
            else
                if grep -q usbfs /proc/filesystems; then
                    mount -t usbfs usbfs /proc/bus/usb
                else
                    mount -t usbdevfs usbdevfs /proc/bus/usb
                fi
            fi
        fi
    fi

    # Load Host Controller Drivers (HCDs) ... this automatically handles
    # systems with multiple controllers (EHCI, OHCI, UHCI) without needing
    # /proc or tools (lspci -v|grep USB, etc) to do so.  If hotplugging
    # is enabled on this system, initting a root hub will cause hotplug
    # events to fire for every device on the tree at that root.

    # FIXME: some of this should be driven by PCI hotplugging, and have
    # the blacklist control which uhci driver gets used (before 2.5).

    # "new style" HCDs ... more common code
    modprobe -q ehci-hcd >/dev/null 2>&1
    modprobe -q ohci-hcd >/dev/null 2>&1
    modprobe -q uhci-hcd >/dev/null 2>&1

    # "old style" HCDs ... more driver-specific bugs
    modprobe -q usb-ohci >/dev/null 2>&1
    # NOTE: this prefers "uhci"; you may prefer "usb-uhci".
    # modprobe -q usb-uhci >/dev/null 2>&1 || modprobe -q uhci >/dev/null 2>&1
    modprobe -q uhci >/dev/null 2>&1 || modprobe -q usb-uhci >/dev/null 2>&1

    # ... add any non-PCI HCDS here.  Examples include the
    # CRIS usb-host, Philips ISP-1161, Symlogic 811HS, and so on.
    # ohci-hcd can handle some non-pci variants.

    if [ -d /proc/bus/usb ]; then
        # If we see there are no busses, we "failed" and
        # can report so even if we're partially nonmodular.
        #
        # NOTE: this fails on older kernels, where usbdevfs had two files
        # ('devices' and 'drivers') with no hcds registered, but works on
        # newer kernels where usbfs has zero files until hcds register,
        # and might not have the 'drivers' file.
        COUNT=`ls /proc/bus/usb | wc -l`
        if [ $COUNT -lt 2 ]; then
            umount /proc/bus/usb
            rmmod usbcore >/dev/null 2>&1
            return 1
        fi

    # if USB is fully modular and yet can clean up,
    # we know init failed without needing usbfs
    elif rmmod usbcore >/dev/null 2>&1; then
        return 1
    fi

    # hotplug events didn't fire during booting;
    # cope with devices that enumerated earlier
    # and may not have been fully configured.
    if [ $SYNTHESIZE = true ]; then
        sleep 1
        usb_boot_events
    fi

    # Some modules are statically loaded, perhaps because they are
    # needed to activate filesystem device nodes.
    for MODULE in $STATIC_MODULE_LIST; do
        modprobe $MODULE
    done

    # we did everything we could ...
    return 0
}

maybe_stop_usb ()
{
    # call this multiple times if you had to take down components of the
    # USB subsystem by hand; it cleans up whatever can
    # be cleaned up, letting the system quiesce further.

    # NOTE:  this list of "all USB modules" is unfortunate, but it seems
    # inevitable until modutils supports the notion of drivers with use
    # counts of zero that shouldn't be removed until after their device
    # gets removed.  Maybe in 2.5 ... of necessity, the list is partial.

    # disconnect all controllers we can, and kernel drivers
    # HCDs first, so most drivers reduce their use counts.
    rmmod ehci-hcd >/dev/null 2>&1
    rmmod ohci-hcd >/dev/null 2>&1
    rmmod uhci-hcd >/dev/null 2>&1
    rmmod usb-ohci >/dev/null 2>&1
    rmmod usb-uhci >/dev/null 2>&1
    rmmod     uhci >/dev/null 2>&1

    # user mode code may keep usbfs busy for a while yet ...

    # OK, usbcore won't actually be removed unless there happen to be
    # no USB drivers loaded, and usbfs isn't mounted.  let's force
    # removal of autocleanable modules before trying to rmmod usbcore
    rmmod -as
# note: module-init-tools 0.8a doesn't handle "-as" flags

    # Now let's workaround the fact that some USB modules never increase
    # their module use counts, so that "rmmod -a" won't unload them.
    # (And we can't use "modprobe --autoclean" anyway.)
    rmmod acm              >/dev/null 2>&1
    rmmod audio            >/dev/null 2>&1
    rmmod auerswald        >/dev/null 2>&1
    rmmod belkin_sa        >/dev/null 2>&1
    rmmod bluetooth        >/dev/null 2>&1
    rmmod catc             >/dev/null 2>&1
    rmmod CDCEther         >/dev/null 2>&1
    rmmod cpia_usb         >/dev/null 2>&1
    rmmod cyberjack        >/dev/null 2>&1
    rmmod dabusb           >/dev/null 2>&1
    rmmod dc2xx            >/dev/null 2>&1
    rmmod digi_acceleport  >/dev/null 2>&1
    rmmod dsbr100          >/dev/null 2>&1
    rmmod emi26            >/dev/null 2>&1
    rmmod empeg            >/dev/null 2>&1
    rmmod ftdi_sio         >/dev/null 2>&1
    rmmod hci_usb          >/dev/null 2>&1
    rmmod hid              >/dev/null 2>&1
    rmmod hpusbscsi        >/dev/null 2>&1
    rmmod ibmcam           >/dev/null 2>&1
    rmmod iforce           >/dev/null 2>&1
    rmmod io_edgeport      >/dev/null 2>&1
    rmmod ipaq             >/dev/null 2>&1
    rmmod ir-usb           >/dev/null 2>&1
    rmmod irda-usb         >/dev/null 2>&1
    rmmod kaweth           >/dev/null 2>&1
    rmmod keyspan          >/dev/null 2>&1
    rmmod keyspan_pda      >/dev/null 2>&1
    rmmod kl5kusb105       >/dev/null 2>&1
    rmmod mct_u232         >/dev/null 2>&1
    rmmod mdc800           >/dev/null 2>&1
    rmmod microtek         >/dev/null 2>&1
    rmmod omninet          >/dev/null 2>&1
    rmmod ov511            >/dev/null 2>&1
    rmmod pegasus          >/dev/null 2>&1
    rmmod pl2303           >/dev/null 2>&1
    rmmod printer          >/dev/null 2>&1
    rmmod pwc pwcx         >/dev/null 2>&1
    rmmod rio500           >/dev/null 2>&1
    rmmod rtl8150          >/dev/null 2>&1
    rmmod scanner          >/dev/null 2>&1
    rmmod se401            >/dev/null 2>&1
    rmmod stv680           >/dev/null 2>&1
    rmmod usbkbd           >/dev/null 2>&1
    rmmod usbmouse         >/dev/null 2>&1
    rmmod usbnet           >/dev/null 2>&1
    rmmod usbtest          >/dev/null 2>&1
    rmmod usb-storage      >/dev/null 2>&1
    rmmod uss720           >/dev/null 2>&1
    rmmod vicam            >/dev/null 2>&1
    rmmod visor            >/dev/null 2>&1
    rmmod wacom            >/dev/null 2>&1
    rmmod whiteheat        >/dev/null 2>&1

    if [ "$STATIC_MODULE_LIST" != "" ]; then
        rmmod $STATIC_MODULE_LIST >/dev/null 2>&1
    fi

    # remove the helper modules that some usb modules need
    rmmod usbserial        >/dev/null 2>&1
    rmmod usbvideo         >/dev/null 2>&1

    # ok, hope that user mode drivers/managers closed their fds.
    umount /proc/bus/usb >/dev/null 2>&1

    rmmod usbcore >/dev/null 2>&1

    # we did everything we could ...
    return 0;
}

# See how we were called.
case "$1" in
  start)
        usb_boot_events
#       maybe_start_usb
        ;;
  stop)
        maybe_stop_usb
        ;;
  status)
        echo $"USB Status for kernel: " `uname -srm`
        echo ''

        if [ -f /proc/bus/usb/devices ]; then
            # as noted above:  this fails on older kernels,
            # where usbfs created files differently.
            COUNT=`ls /proc/bus/usb | wc -l`
            if [ $COUNT -ge 2 ]; then
                COUNT=`expr $COUNT - 2`
                echo $"USB up; bus count is $COUNT"
                grep "^[TPSI]:" /proc/bus/usb/devices
            else
                echo $"usbfs partially up; no busses"
            fi
            echo ''

            echo $"USB Drivers Loaded: "
            if [ -f /proc/bus/usb/drivers ]; then
                cat /proc/bus/usb/drivers
            fi
            if [ -d /sys/bus/usb ]; then
                ls -1 /sys/bus/usb/drivers
            fi
        else
            echo $"usbfs is unavailable. "
            if [ -f /proc/modules ] && fgrep -q usbcore /proc/modules; then
                echo $"USB module is loaded. "
            else
                echo $"USB may be statically linked. "
            fi
            echo $"If khubd is running, that shows USB is available."
        fi
        echo ''

        if [ -f /proc/sys/kernel/hotplug ]; then
            echo $"khubd/hotplug thread: "
        else
            echo $"khubd thread:"
        fi
        ps -l | head -1
        ps -Al | egrep 'khubd' | grep -v grep
        echo ''

        lsmod
        echo ''

        # /proc/devices too? "usb", "input", and others ...

        ;;
  restart)
        # always invoke by absolute path, else PATH=$PATH:
        $0 stop && $0 start
        ;;
  *)
        echo $"Usage: $0 {start|stop|status|restart}"
        exit 1
esac
#!/bin/sh
#
# USB-specific hotplug policy agent.
#
# This should handle 2.2.18+, 2.4.*, and 2.5.* USB hotplugging,
# with a consistent framework for adding device and driver
# specific handling.
#
# Normally, adding a usb device will modprobe a driver.  If there
# is a /etc/hotplug/usb/$DRIVER script set up, it will also run,
# handling tasks like loading firmware or starting daemons.
#
# Kernel USB hotplug params include:
#       
#       ACTION=%s [add or remove]
#       DEVPATH=%s [in 2.5 kernels, /sys/$DEVPATH]
#       PRODUCT=%x/%x/%x
#       INTERFACE=%d/%d/%d [ for interface 0, if TYPE=0/*/* ]
#       TYPE=%d/%d/%d
#
# And if usbfs (originally called usbdevfs) is configured, also:
#
#       DEVFS=/proc/bus/usb [gone in 2.5]
#       DEVICE=/proc/bus/usb/%03d/%03d
#
# This script then adds the variable:
#
#       REMOVER=/var/run/usb/<some string unique to $DEVICE>
#
# This is the path where the script would like to find a remover, if
# the target device needs one. This script is executed on remove if
# it is executable when the remove happens.
#
# If usbfs is mounted on /proc/bus/usb, $DEVICE is a file which
# can be read to get the device's current configuration descriptor.
# (The "usbmodules" utility does that.)  Or it can be used by a
# user mode driver to interact with the usb device.  USB hotplug
# does *not* require usbfs (or sysfs) to work, although on 2.4
# some devices work better if "usbmodules" can help.
#
# For Linux 2.5+ kernels, there's no need for "usbmodules".  For
# two reasons:  first, hotplug is invoked for each interface, not
# just the first one.  Second, sysfs exposes descriptors so they
# are easy to use for "coldplug" event simulation.  (But sysfs is
# not a replacement for the driver I/O capabilities in usbfs.)
#
# On systems using Linux 2.4.* kernels, be sure to use the right
# modutils (2.4.2+).  That ensures that hotplugging uses the list
# of modules installed for your kernel, rather than the one that's
# included here for use on systems without MODULE_DEVICE_TABLE
# support.
#
#
# HISTORY:
#
# 20-Nov-2002   some 2.5 updates; handle new 'device' hotplug; turn off
#               'sleep' hack since hcds must all queue control traffic
# 08-Aug-2002   support for multiple usermaps (maxk), minor cleanup
# 18-Jan-2002   fix match algorithm in usb_map_modules()
# 14-Jan-2002   fix work around 2.2 brokeness of $PRODUCT
# 09-Jan-2002   REMOVER for system without usbdevfs
#
# 14-Mar-2001   Cleanup, bitmask the match_flags
# 26-Feb-2001   Cleanup, support comments (Gioele Barabucci)
# 15-Feb-2001   Remove use of "<<" (Adam Richter)
# 23-Jan-2001   Update 2.2 handling; unfortunately there's no "feature
#               test" that can work robustly
# 05-Jan-2001   Quick hack for kernel 2.4.0 and modutils 2.4.1
# 03-Jan-2001   Initial version of "new" hotplug agent, using feedback
#               and contributions from Adam Richter, Ryan VanderBijl,
#               Norbert Preining, Florian Lohoff, David Brownell and
#               others.  To replace the original /etc/usb/policy. (db)
#
# $Id: usb.agent,v 1.41 2004/04/01 07:30:26 kroah Exp $
#

if [ -f /etc/sysconfig/usb ]; then
    . /etc/sysconfig/usb
fi
if [ -f /etc/conf.d/usb ]; then
    . /etc/conf.d/usb
fi

cd /etc/hotplug
. ./hotplug.functions
# DEBUG=yes export DEBUG

# generated by modutils, for current 2.4.x (and later) kernels
MAP_CURRENT=$MODULE_DIR/modules.usbmap

# used if MAP_CURRENT is missing; for 2.2.x kernels
MAP_DISTMAP=$HOTPLUG_DIR/usb.distmap

#
# used for kernel drivers that don't show up in CURRENT or DISTMAP,
# currently input drivers (joysticks, keyboards, etc).  newer systems
# should use input hotplug events instead.
#
MAP_HANDMAP=$HOTPLUG_DIR/usb.handmap

#
# used to run config scripts for user mode drivers (jPhoto, gPhoto2,
# rio500 tools, etc) ... instead of naming kernel modules, it names
# config scripts.  those could change $DEVICE permissions, etc.
#
# for purely user mode drivers, scripts $HOTPLUG_DIR/usb/NAME should be
# installed with usermap files in $HOTPLUG_DIR/usb/NAME.usermap instead
# of continuing to use/modify $MAP_USERMAP 
#
MAP_USERMAP=$HOTPLUG_DIR/usb.usermap


# accumulates list of modules we may care about
DRIVERS=""

if [ "$ACTION" = "" ]; then
    mesg Bad USB agent invocation, no action
    exit 1
fi

# starting in kernel 2.5 there are two kinds of USB hotplug events.
# - per-interface; 2.2/2.4 kernels only reported the first one.
#       "new" events have nonzero /sys/$DEVPATH/bInterfaceNumber
# - per-device; "new" events don't have $PRODUCT
SYSFS=/sys
if [ "$PRODUCT" = "" ]; then
    # this is either an error, or we're on a 2.5 system...
    if [ "$DEVPATH" = "" ]; then
        mesg Bad USB agent invocation
        exit 1
    fi

    # sysfs files may already be gone
    if [ $ACTION = 'remove' ]; then
        exit 0
    fi

    # we could be running before usb populated these attributes...
    if [ ! -f $SYSFS/$DEVPATH/bNumConfigurations ]; then
        # FIXME wait till they appear, or N seconds elapse
        sleep 2
    fi

    # this could care about changing the default config, or warning
    # when the user hooked a fast device up so it runs slowly.
    if [ ! -f $SYSFS/$DEVPATH/bNumConfigurations ]; then
        exit 0
    fi
    TMP=$(cat $SYSFS/$DEVPATH/bNumConfigurations)
    if [ $TMP -ne 1 -a "$ACTION" = add ]; then
        mesg Keeping default configuration with $SYSFS/$DEVPATH
    fi

    # NOTE:  it might be good to add an extension hook here rather
    # than ignore these events, but even device-scope tasks such
    # as firmware download can still use the interface-0 event
    # (as they did with 2.2/2.4 hotplug setup scripts).
    exit 0
fi

# we can't "unset IFS" on bash1, so save a copy
DEFAULT_IFS="$IFS"

#
# Each modules.usbmap format line corresponds to one entry in a
# MODULE_DEVICE_TABLE(usb,...) 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.
#

usb_convert_vars ()
{
    # work around 2.2.early brokenness
    # munges the usb_bcdDevice such that it is a integer rather
    # than a float: e.g. 1.0 become 0100
    PRODUCT=`echo $PRODUCT | sed -e "s+\.\([0-9]\)$+.\10+" -e "s/\.$/00/" \
                                  -e "s+/\([0-9]\)\.\([0-9][0-9]\)+/0\1\2+" \
                          -e "s+/\([0-9][0-9]\)\.\([0-9][0-9]\)+/\1\2+"`
    set $(echo $PRODUCT | sed -e 's+\([^/]*\)/\([^/]*\)/\(.*\)+\1 \2 \3+')
    usb_idVendor=$((0x$1))
    usb_idProduct=$((0x$2))
    usb_bcdDevice=$((0x$3))

    if [ "$TYPE" != "" ]; then
        IFS=/
        set $TYPE ''
        usb_bDeviceClass=$1
        usb_bDeviceSubClass=$2
        usb_bDeviceProtocol=$3
        IFS="$DEFAULT_IFS"
    elif [ -r $SYSFS/$DEVPATH/bDeviceClass ]; then
        usb_bDeviceClass=$((0x$(cat $SYSFS/$DEVPATH/bDeviceClass)))
        usb_bDeviceSubClass=$((0x$(cat $SYSFS/$DEVPATH/bDeviceSubClass)))
        usb_bDeviceProtocol=$((0x$(cat $SYSFS/$DEVPATH/bDeviceProtocol)))
    else
        # out-of-range values
        usb_bDeviceClass=1000
        usb_bDeviceSubClass=1000
        usb_bDeviceProtocol=1000
    fi

    if [ "$INTERFACE" != "" ]; then
        IFS=/
        set $INTERFACE ''
        usb_bInterfaceClass=$1
        usb_bInterfaceSubClass=$2
        usb_bInterfaceProtocol=$3
        IFS="$DEFAULT_IFS"
    elif [ -r $SYSFS/$DEVPATH/bInterfaceClass ]; then
        usb_bInterfaceClass=$((0x$(cat $SYSFS/$DEVPATH/bInterfaceClass)))
        usb_bInterfaceSubClass=$((0x$(cat $SYSFS/$DEVPATH/bInterfaceSubClass)))
        usb_bInterfaceProtocol=$((0x$(cat $SYSFS/$DEVPATH/bInterfaceProtocol)))
    else
        # out-of-range values
        usb_bInterfaceClass=1000
        usb_bInterfaceSubClass=1000
        usb_bInterfaceProtocol=1000
    fi
}

USB_MATCH_VENDOR=$((0x0001))
USB_MATCH_PRODUCT=$((0x0002))
USB_MATCH_DEV_LO=$((0x0004))
USB_MATCH_DEV_HI=$((0x0008))
USB_MATCH_DEV_CLASS=$((0x0010))
USB_MATCH_DEV_SUBCLASS=$((0x0020))
USB_MATCH_DEV_PROTOCOL=$((0x0040))
USB_MATCH_INT_CLASS=$((0x0080))
USB_MATCH_INT_SUBCLASS=$((0x0100))
USB_MATCH_INT_PROTOCOL=$((0x0200))

#
# stdin is "modules.usbmap" syntax
# on return, all matching modules were added to $DRIVERS
#
usb_map_modules ()
{
    local line module

    # look at each usb_device_id entry
    # collect all matches in $DRIVERS

    while read line
    do
        # comments are lines that start with "#" ...
        # be careful, they still get parsed by bash!
        case "$line" in
        \#*) continue ;;
        esac

        set $line

        module=$1
        match_flags=$(($2))

        idVendor=$(($3))
        idProduct=$(($4))
        bcdDevice_lo=$(($5))
        bcdDevice_hi=$(($6))

        bDeviceClass=$(($7))
        bDeviceSubClass=$(($8))
        bDeviceProtocol=$(($9))

        shift 9
        bInterfaceClass=$(($1))
        bInterfaceSubClass=$(($2))
        bInterfaceProtocol=$(($3))

        : checkmatch $module

        : idVendor $idVendor $usb_idVendor
        if [ $USB_MATCH_VENDOR -eq $(( $match_flags & $USB_MATCH_VENDOR )) ] && 
           [ $idVendor -ne $usb_idVendor ]; then
            continue
        fi

        : idProduct $idProduct $usb_idProduct
        if [ $USB_MATCH_PRODUCT -eq $(( $match_flags & $USB_MATCH_PRODUCT )) ] 
&&
           [ $idProduct -ne $usb_idProduct ]; then
            continue
        fi

        : bcdDevice range $bcdDevice_hi $bcdDevice_lo actual $usb_bcdDevice
        if [ $USB_MATCH_DEV_LO -eq $(( $match_flags & $USB_MATCH_DEV_LO )) ] &&
           [ $usb_bcdDevice -lt $bcdDevice_lo ]; then
            continue
        fi

        # bcdDevice_lo <= bcdDevice <= bcdDevice_hi
        if [ $USB_MATCH_DEV_HI -eq $(( $match_flags & $USB_MATCH_DEV_HI )) ] &&
           [ $usb_bcdDevice -gt $bcdDevice_hi ]; then
            continue
        fi

        : bDeviceClass $bDeviceClass $usb_bDeviceClass
        if [ $USB_MATCH_DEV_CLASS -eq $(( $match_flags & $USB_MATCH_DEV_CLASS 
)) ] &&
           [ $bDeviceClass -ne $usb_bDeviceClass ]; then
            continue
        fi
        : bDeviceSubClass $bDeviceSubClass $usb_bDeviceSubClass
        if [ $USB_MATCH_DEV_SUBCLASS -eq $(( $match_flags & 
$USB_MATCH_DEV_SUBCLASS )) ] &&
           [ $bDeviceSubClass -ne $usb_bDeviceSubClass ]; then
            continue
        fi
        : bDeviceProtocol $bDeviceProtocol $usb_bDeviceProtocol
        if [ $USB_MATCH_DEV_PROTOCOL -eq $(( $match_flags & 
$USB_MATCH_DEV_PROTOCOL )) ] &&
           [ $bDeviceProtocol -ne $usb_bDeviceProtocol ]; then
            continue
        fi

        # NOTE:  for now, this only checks the first of perhaps
        # several interfaces for this device.

        : bInterfaceClass $bInterfaceClass $usb_bInterfaceClass
        if [ $USB_MATCH_INT_CLASS -eq $(( $match_flags & $USB_MATCH_INT_CLASS 
)) ] &&
           [ $bInterfaceClass -ne $usb_bInterfaceClass ]; then
            continue
        fi
        : bInterfaceSubClass $bInterfaceSubClass $usb_bInterfaceSubClass
        if [ $USB_MATCH_INT_SUBCLASS -eq $(( $match_flags & 
$USB_MATCH_INT_SUBCLASS )) ] &&
           [ $bInterfaceSubClass -ne $usb_bInterfaceSubClass ]; then
            continue
        fi
        : bInterfaceProtocol $bInterfaceProtocol $usb_bInterfaceProtocol
        if [ $USB_MATCH_INT_PROTOCOL -eq $(( $match_flags & 
$USB_MATCH_INT_PROTOCOL )) ] &&
           [ $bInterfaceProtocol -ne $usb_bInterfaceProtocol ]; then
            continue
        fi

        # It was a match!
        DRIVERS="$module $DRIVERS"
        : drivers $DRIVERS
    done
}

#
# declare a REMOVER name that the add action can use to create a
# remover, or that the remove action can use to execute a remover.
#
if [ "$DEVPATH" != "" ]; then
  # probably, 2.6.x
  REMOVER=/var/run/usb/$(readlink -f $SYSFS/$DEVPATH | sed -e 's;/;%;g')
elif [ "$DEVICE" != "" ]; then
  # 2.4.x?
  REMOVER=/var/run/usb/$(echo $DEVICE | sed -e 's;/;%;g')
else
  # should not happen?
  REMOVER=/var/run/usb/$(echo "$INTERFACE/$PRODUCT/$TYPE" | sed -e 's;/;%;g')
fi
export REMOVER

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

add)
    # partial workaround for 2.4 uhci/usb-uhci driver problem:  they don't
    # queue control requests, so device drivers can confuse each other if
    # they happen to issue requests at the same time ... it happens easily
    # with slow HID devices and "usbmodules".
    # starting with 2.5 (DEVPATH set), all hcds must queue control traffic.
    if [ "$DEVPATH" = "" ]; then
        sleep 3
    fi

    usb_convert_vars

    FOUND=false
    if [ -f $SYSFS/$DEVPATH/manufacturer ]; then
        LABEL="USB `cat $SYSFS/$DEVPATH/manufacturer` `cat 
$SYSFS/$DEVPATH/product`"
    else
        LABEL="USB product $PRODUCT"
    fi

    if [ -e "$REMOVER" ]; then
        rm -f "$REMOVER"
    fi

    # on 2.4 systems, modutils 2.4.2+ maintains MAP_CURRENT
    # ... otherwise we can't rely on it (sigh)
    case "$KERNEL" in
    2.4.*|2.5.*|2.6.*)
        if [ -r $MAP_CURRENT ]; then
            load_drivers usb $MAP_CURRENT "$LABEL"
        fi;;
    *)
        if [ -r $MAP_DISTMAP ]; then
            load_drivers usb $MAP_DISTMAP "$LABEL"
        fi;;
    esac
    if [ "$DRIVERS" != "" ]; then
        FOUND=true
    fi

    # cope with special driver module configurations
    # (mostly HID devices, until we have an input.agent)
    # not needed on 2.6 - they are loaded by hotplug
    case "$KERNEL" in
        2.6.* )
            : nothing
        ;;
        * )
            if [ -r $MAP_HANDMAP ]; then
                load_drivers usb $MAP_HANDMAP "$LABEL"
                if [ "$DRIVERS" != "" ]; then
                    FOUND=true
                fi
            fi
        ;;
    esac

    # some devices have user-mode drivers (no kernel module, but config)
    # or specialized user-mode setup helpers 
    MODPROBE=:
    for MAP in $MAP_USERMAP $HOTPLUG_DIR/usb/*.usermap
    do
        if [ -r $MAP ]; then
            load_drivers usb $MAP "$LABEL"
            if [ "$DRIVERS" != "" ]; then
                FOUND=true
            fi
        fi
    done

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

remove)
    if [ -x $REMOVER ]; then
        $REMOVER
    fi
    rm -f $REMOVER

    if [ -x /usr/sbin/updfstab ]; then
        /usr/sbin/updfstab
    fi
    ;;

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

esac

Reply via email to