#!/bin/sh
# rustic hardware probing
# M. Andreoli

. /etc/utils

#set -x

# Syntax

log_success()
{
wave -c 220 1; wave -c 440 1 ; wave -c 880 4
}

usage()
{
cat <<END
muLinux rustic hardware probing
(C) M. Andreoli

Usage:	scan [options] [hardware]

and "hardware" is: 

	mouse, modem, ide-cdrom, scsi-bus, scsi-cdrom
	scsi-hd, ide-hd, tcp, pci, irq

Generally, return  a device's list in the form /dev/XYZ /dev/ ...
END
exit

}

# LOCAL


# use dmesg cache, because it disapper 

DMESG()
{
LOG=/var/log
[ ! -d $LOG ] && LOG=/tmp
if [ ! -f $LOG/dmesg ] ; then
	dmesg > $LOG/dmesg
fi
	cat $LOG/dmesg
}

# find cdrom


search_for()
{
local string="$@"
save=$IFS; IFS=":"
set -- `DMESG| sed -n /$string/P`
[ "$1" ] && echo $1 && return 0
return 1
}

scan_cdrom()
{

id=$(search_for "ATAPI CDROM") || \
id=$(search_for "CD-ROM") || \
id=$(search_for "CDROM")

case "${id}" in
hd*)
        echo "/dev/$id"
	return 0
	;;
*)
	echo "/dev/null"
	return 1
esac

}

mouse_protocol()
{
case $1 in
*ttyS*)
	echo "ms";;
*psaux)
	echo "ps2";;
esac
}

# return the IRQ that respond to a given device
 
irq_from_device()
{
local dev=$1
case $dev in
*ttyS*)
	set -- `setserial -v -b $dev auto_irq \
	skip_test autoconfig session_lockout`
	[ "$6" ] && echo $6 | tr -d \) 
	;;
*psaux*)
	set -- `cat /proc/interrupts | rgrep PS/2`
	if [ "$1" ]; then
		echo $1 | tr -d :		
	else
		echo 12	# standard irq for ps2 mouse
	fi
	;;
esac

}

# return the device that respond to a given IRQ

device_from_irq()
{
local irq=$1
[ -z "$irq" ] && echo "/dev/null" && return 1
for d in /dev/ttyS0 /dev/ttyS1 /dev/ttyS2 /dev/ttyS3 /dev/psaux; do
	[ "$irq" = "$(irq_from_device $d)" ] && echo $d && return 0
done
echo "/dev/null"
return 1
}

# kill processing attached to device

kill_users()
{
[ "`which fuser`" ] && fuser -k $1 2>/dev/null
}

chat_with()
{
(
echo -e "AT^M"
timeout 3 2>/dev/null
if [ $? -eq 0 ] ; then
         echo 1 > /tmp/m
else
        echo 0 > /tmp/m
fi
) < $1 > $1

return `cat /tmp/m`
}


# usage: probe_modem /dev/x

probe_modem()
{
dev=$1
local irq
irq=$(irq_from_device $dev)
[ -z "$irq" ] && return 1

kill_users $dev
chat_with $dev || return 1
}

# Usage list_block {sd|hd| ...}

list_block()
{
prefix=$1
cdrom=`scan_cdrom`

for x in a b c d e f
do
if [ /dev/${prefix}$x != "$cdrom" ] ; then  
(echo "p"; echo "q") | fdisk /dev/${prefix}${x} 2>/dev/null |\
sed -n "/^\/dev\/${prefix}/P" | sed "s/\*/A/g"
fi
done
}

# usage: irq_count irq_number
# See /proc/stat

irq_count()
{
local irq=$1
set -- `cat /proc/stat | rgrep intr`
shift 3 # only 1,2,3 (not irq=0) 
if [ "$irq" -lt 10 ] ; then
	eval echo \$${irq}
else
	shift 10
	irq=`expr $irq % 10`	# modulo 10
	eval echo \$${irq}
fi
}

# usage: irq_probe irq_number
# See /proc/stat

irq_probe()
{
local irq=$1
max=3
count=1

# start value
start=$(irq_count $irq)

while [ $count -lt $max ] ; do
now=$(irq_count $irq)
[ $now -ne $start ] && [ "$now" ] && return 0
sleep 1
count=`expr $count + 1`
done
return 1
}

log()
{
echo "$@" 1>&2
}

scsi_bus()
{
cat /proc/scsi/scsi 2>/dev/null \
| rgrep -v "Attached devices:" | rgrep -v "Vendor:" |\
sed s/[A-z]*://g |
while 
do
read host CH ID LUN 
[ -z "$host" ] && break
read type dummy

echo "$type $CH $ID $LUN"

done
}

partition_info()
{
while read entry 
do
set -- $entry
dev=$1; shift
boot="$1";
if [ "$boot" = 'A' ]; then
	shift
else
	boot=
fi
begin=$1; shift
start=$1; shift
end=$1; shift
blocks=$1; shift
id=$1; shift
fs=$@

[ $id = "5" ] && continue	# extended partions

# probe
dd if=$dev of=/dev/null bs=1c count=1 2>/dev/null || continue 

os=`get_os`

case "Z${options}Z" in
ZZ)
	echo $dev
	;;
Z-fZ)
	echo "$dev $os"
	;;
esac

done
}

get_os()
{
case $id in
4|6|b|c|e)	
	echo "Windows"
	;;
83)
	echo "Linux"
	;;
*)	
	echo "Unsupported"
esac
}
# save irq value in the 'array' form x,y,z,....

save_irqs()
{
local f=$1
set -- `cat /proc/stat | rgrep intr`
shift 3
echo "$@" | tr " " "," > $f 
}

# syntax: [irq_list]

return_changed_irq()
{
local irq_list
local old
local new

irq_list="$@"
all_irq="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
[ -z "${irq_list}" ] && irq_list="${all_irq}"

old_irq=$(cat /tmp/before)
new_irq=$(cat /tmp/after)

for i in ${irq_list}; do
old=$(Array ${old_irq} $i)
new=$(Array ${new_irq} $i)
[ "$new" -gt $old ] && echo "$i" && return 0
done
return 1
}


detect_psaux()
{
rmmod psaux 2>/dev/null
insmod psaux
}

# MAIN


if [ $# -eq 1 ]; then
	options=; R=$1
elif [ $# -eq 0 ]; then
	usage
else
	options="$1"; R="$2"
fi

case $R in
irq)	# detect is an IRQ is triggered in 5 secs
	log "Waiting (5 secs) ..."
	save_irqs /tmp/before
	sleep 5 
	save_irqs /tmp/after
	irq=`return_changed_irq` ; rm /tmp/before 2>/dev/null
	if [ "$irq" ] ; then
		log "triggered IRQ=$irq."
	else
		log "none triggered."
	fi	
	;;
mouse-old)
	#detect_psaux && echo "/dev/psaux" && exit 0 
        # load relevants kernel drivers
	(
        insmod serial; insmod psaux
        [ -z "$DISPLAY" ] && gpm -m /dev/psaux -t ps2 -r 10
        ) 2>/dev/null
	log "Please, move your mouse in next 2 seconds ..."
	save_irqs /tmp/before
	sleep 2 
	save_irqs /tmp/after
	irq=`return_changed_irq 3 4 12` 
	rm /tmp/before /tmp/after 2>/dev/null
	device=$(device_from_irq $irq)
	if [ "$device" != /dev/null ] ; then
		log "Detected device=$device, IRQ [$irq]! "
	else
		log "Can't find the mouse."
	fi	
	echo $device
	;;
mouse)	# scan for mouse device

	#detect_psaux && echo "/dev/psaux" && exit 0 

	# load relevants kernel drivers
	insmod psaux
        (cat /proc/devices| rgrep ttyS > /dev/null) || insmod serial

	log "The (rustic) probe works only if no spurious devices" 
	log "are using the ports (such pppd, etc)" 
	log ""
	log "Please, move your mouse now, thank you ..."
	for dev in /dev/ttyS0 /dev/ttyS1 /dev/ttyS2 /dev/ttyS3 /dev/psaux
	do
	irq=`irq_from_device $dev`
	if [ "$irq" ] ; then
	wave -c 110 1
	log "Scanning $dev ($(speak_dos $dev) irq $irq) ... (3 secs)"
		kill_users $dev
		gpm -k 2>/dev/null
		gpm -m $dev -t $(mouse_protocol $dev) -r 10
		if irq_probe $irq; then
		log_success
       		log "Ok, mouse is $dev, IRQ=$irq. Congratulations! "
		gpm -k
		echo $dev; exit 0
		fi
	fi
	done

	gpm -k
        log "Sorry, can't locate your mouse."
	echo /dev/null; exit 1 
;;

ide-cdrom|IDE-cdrom) # probe ide cdrom

	scan_cdrom
	return $?
;;
scsi-cdrom|SCSI-cdrom) # probe scsi cdrom
	:	
	cdrom=`scsi_bus | sed -n /CD.*ROM/P` 
	if [ "$cdrom" ] ; then
	set -- $cdrom; id=`expr $2 + 0`
	echo /dev/scd${id}
	return 0
	fi
	return 1
	;;
scsi-hd|SCSI-hd) # probe scsi HD

	list_block sd | partition_info $options
	;;
ide-hd|IDE-hd) # probe IDE HD

        list_block hd | partition_info $options
	;;
scsi-bus)
	:
	scsi_bus
	;;
tcp)
	nmap localhost
	;;
scsi-bus)
	scsi_bus
	;;
tcp)
	nmap localhost
	;;
modem)
	rmmod serial 2>/dev/null
	(cat /proc/devices| rgrep ttyS >/dev/null) || insmod serial
	serial="/dev/ttyS0 /dev/ttyS1 /dev/ttyS2 /dev/ttyS3"	
	for d in ${serial} 
	do
	if [ "$(irq_from_device $d)" ] ; then
	wave -c 110 1
	echo -n "Probing $d ($(speak_dos $d)) ... " 1>&2
	probe_modem $d && echo "OK" 1>&2 && echo $d && log_success && exit 0 
	echo "not responding." 1>&2
	fi
	done
	echo /dev/null
	exit 1
	;;	
pci)
	cat /proc/pci| rgrep -v Bus | rgrep : 
	;;
*)
	echo "Error."
	usage
	;;
esac
