#!/bin/bash # $Id$ # # input-device specific hotplug policy agent. # # This should handle 2.6.* input hotplugging, # with a consistent framework for adding device and driver # specific handling. # # Normally, adding a input device will modprobe handler(s) for # this device. # # Kernel input hotplug params include (not all of them may be available): # # ACTION=%s [add or remove] # PRODUCT=%x/%x/%x/%x # NAME=%s # PHYS=%s # EV=%lx # KEY=%lx %lx ... # REL=%lx # ABS=%lx %lx ... # MSC=%lx # LED=%lx # SND=%lx # FF=%lx %lx ... # : ${ACTION?Bad invocation: \$ACTION is not set} cd /etc/hotplug . ./hotplug.functions # generated by module-init-tools MAP_CURRENT=$MODULE_DIR/modules.inputmap # used for kernel drivers that don't show up in MAP_CURRENT # or to overwrite default from MAP_CURRENT # MAP_HANDMAP=$HOTPLUG_DIR/input.handmap # Each modules.inputmap format line corresponds to one entry in a # MODULE_DEVICE_TABLE(input,...) declaration in a kernel file. # matchBits=0 i_bustype=0 i_vendor=0 i_product=0 i_version=0 i_evBits=0 input_join_words () { local name=$1; shift local tmp=$1; shift while [ "$#" -gt 0 ]; do tmp="$tmp:$1"; shift done eval $name=\$tmp } input_convert_vars () { if [ "$PRODUCT" != "" ]; then set -- `IFS=/; echo $PRODUCT` i_bustype=$((0x$1)) i_vendor=$((0x$2)) i_product=$((0x$3)) i_version=$((0x$4)) fi if [ "$EV" != "" ]; then i_evBits=$((0x$EV)) fi input_join_words i_keyBits $KEY # for a in $KEY; do i_keyBits="${i_keyBits:+$i_keyBits:}${a}"; done input_join_words i_relBits $REL input_join_words i_absBits $ABS input_join_words i_mscBits $MSC input_join_words i_ledBits $LED input_join_words i_sndBits $SND input_join_words i_ffBits $FF } INPUT_DEVICE_ID_MATCH_BUS=1 INPUT_DEVICE_ID_MATCH_VENDOR=2 INPUT_DEVICE_ID_MATCH_PRODUCT=4 INPUT_DEVICE_ID_MATCH_VERSION=8 INPUT_DEVICE_ID_MATCH_EVBIT=$((0x010)) INPUT_DEVICE_ID_MATCH_KEYBIT=$((0x020)) INPUT_DEVICE_ID_MATCH_RELBIT=$((0x040)) INPUT_DEVICE_ID_MATCH_ABSBIT=$((0x080)) INPUT_DEVICE_ID_MATCH_MSCBIT=$((0x100)) INPUT_DEVICE_ID_MATCH_LEDBIT=$((0x200)) INPUT_DEVICE_ID_MATCH_SNDBIT=$((0x400)) INPUT_DEVICE_ID_MATCH_FFBIT=$((0x800)) input_match_bits () { local mod_bits=$1 dev_bits=$2 mword=$((0x${mod_bits##*:})) dword=$((0x${dev_bits##*:})) while true; do if [ $(( $mword & $dword != $mword )) -eq 1 ]; then return 1 fi mod_bits=${mod_bits%:*} dev_bits=${dev_bits%:*} case "$mod_bits-$dev_bits" in *:*-*:* ) : continue ;; *:*-*|*-*:* ) return 0 ;; * ) return 1 ;; esac done } # # stdin is "modules.inputmap" syntax # on return, all matching modules were added to $DRIVERS # input_map_modules () { local line module local relBits mscBits ledBits sndBits keyBits absBits ffBits 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 matchBits=$(($2)) bustype=$(($3)) vendor=$(($4)) product=$(($5)) vendor=$(($6)) evBits=$(($7)) keyBits=$8 relBits=$(($9)) shift 9 absBits=$(($1)) cbsBits=$(($2)) ledBits=$(($3)) sndBits=$(($4)) ffBits=$(($5)) driverInfo=$(($6)) : checkmatch $module : bustype $bustype $i_bustype if [ $INPUT_DEVICE_ID_MATCH_BUS -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_BUS )) ] && [ $bustype -ne $i_bustype ]; then continue fi : vendor $vendor $i_vendor if [ $INPUT_DEVICE_ID_MATCH_VENDOR -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_VENDOR )) ] && [ $vendor -ne $i_vendor ]; then continue fi : product $product $i_product if [ $INPUT_DEVICE_ID_MATCH_PRODUCT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_PRODUCT )) ] && [ $product -ne $i_product ]; then continue fi # version i_version $i_version < version $version if [ $INPUT_DEVICE_ID_MATCH_VERSION -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_VERSION )) ] && [ $version -ge $i_version ]; then continue fi : evBits $evBits $i_evBits if [ $INPUT_DEVICE_ID_MATCH_EVBIT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_EVBIT )) ] && [ $evBits -ne $(( $evBits & $i_evBits)) ]; then continue fi : keyBits $keyBits $i_keyBits if [ $INPUT_DEVICE_ID_MATCH_KEYBIT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_KEYBIT )) ] && input_match_bits "$keyBits" "$i_keyBits"; then continue fi : relBits $relBits $i_relBits if [ $INPUT_DEVICE_ID_MATCH_RELBIT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_RELBIT )) ] && [ $relBits -ne $(( $relBits & $i_relBits)) ]; then continue fi : absBits $absBits $i_absBits if [ $INPUT_DEVICE_ID_MATCH_ABSBIT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_ABSBIT )) ] && input_match_bits "$absBits" "$i_absBits"; then continue fi : mscBits $mscBits $i_mscBits if [ $INPUT_DEVICE_ID_MATCH_MSCBIT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_MSCBIT )) ] && [ $mscBits -ne $(( $mscBits & $i_mscBits)) ]; then continue fi : ledBits $ledBits $_ledBits if [ $INPUT_DEVICE_ID_MATCH_LEDBIT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_LEDBIT )) ] && input_match_bits "$ledBits" "$i_ledBits"; then continue fi : sndBits $sndBits $i_sndBits if [ $INPUT_DEVICE_ID_MATCH_SNDBIT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_SNDBIT )) ] && [ $sndBits -ne $(( $sndBits & $i_sndBits)) ]; then continue fi : ffBits $ffBits $i_ffBits if [ $INPUT_DEVICE_ID_MATCH_FFBIT -eq $(( $matchBits & $INPUT_DEVICE_ID_MATCH_FFBIT )) ] && input_match_bits "$ffBits" "$i_ffBits"; then continue fi : driverInfo $driverInfo if [ $matchBits -eq 0 -a $driverInfo -eq 0 ]; then continue fi # It was a match! case " $DRIVERS " in *" $module "* ) : already found ;; * ) DRIVERS="$module $DRIVERS" ;; esac : drivers $DRIVERS done } # # What to do with this INPUT hotplug event? # case $ACTION in add) # If hwup does initialize the device there is nothing more to do if [ -x /sbin/hwup ] && /sbin/hwup ${1:+$1-}devpath-$DEVPATH -o hotplug; then : nix else input_convert_vars FOUND="" LABEL="INPUT product $PRODUCT" # cope with special driver module configurations first. So we can # overwrite default settings in MAP_CURRENT if [ -r $MAP_HANDMAP ]; then load_drivers usb $MAP_HANDMAP "$LABEL" FOUND="$FOUND${DRIVERS:+ $DRIVERS}" fi if [ -r $MAP_CURRENT -a -z "$FOUND" ]; then load_drivers input $MAP_CURRENT "$LABEL" fi fi ;; remove) if [ -x /sbin/hwdown ] && /sbin/hwdown ${1:+$1-}devpath-$DEVPATH -o hotplug; then : nix fi ;; *) debug_mesg INPUT $ACTION event not supported exit 1 ;; esac