# -*- shell-script -*-

# 07device_ide_proc - IDE device support using /proc/ide.

# This file is part of the Linux lsvpd package.

# (C) Copyright IBM Corp. 2003, 2004

# Maintained by Martin Schwenke <martins@au.ibm.com>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    
# $Id: 07device_ide_proc,v 1.23 2004/10/22 07:24:42 martins Exp $

[ -d "/proc/ide" ] || return 0

######################################################################

device_setup_ide ()
{
    local f="${db_misc_dir}/ide_map"
    rm -f "$f"
    >"$f"

    local s
    for s in /proc/ide/ide*/*/settings ; do
	local devd="${s%/*}"      # dirname
	local dev="${devd##*/}"   # basename
	local chand="${devd%/*}"  # dirname
	local chan="${chand##*/}" # basename

	local name value min max mode
	while read name value min max mode ; do
	    if [ "$name" = "number" -a \
		 -n "$value" -a -n "$min" -a -n "$max" ] ; then
		local range=$(($max - $min + 1))
		local mf="${chand}/mate"
		if [ -f "$mf" ] ; then
		    local mate
		    read mate <"$mf"
		    case "$mate" in
			(ide*) range=$(($range / 2));;
		    esac
		fi
		local channel="${chan#ide}"
		local unit=$(($value % $range))
	    
		echo "/dev/${dev} ${channel}.${unit}" >>"$f"
		break
	    fi
	done <"$s"
    done
}

list_devices_ide ()
{
    sed -n -e 's/^[^ ][^ ]*  *\([0-9][0-9]*\.[0-9][0-9]*\)$/\1/p' \
	"${db_misc_dir}/ide_map"
}

add_device_ide ()
{
    local cu="$1"  # channel.unit

    local dev=$(get_kernel_device_name_ide "$cu")
    local name="${dev##*/}" # basename

    local d="/proc/ide/${name}"

    if [ -d "$d" ] ; then
	local if="${d}/identify"
	local tf="${d}/media"
	local sf="${d}/settings"
	local os_prefix=$(get_adapter_os_prefix "ide")

	if [ -f "$if" -a -f "$tf" -a -f "$sf" ] ; then

	    local l adapter device_type
	    l=$(readlink "$d")
	    adapter="${l%/*}" # dirname
	    read device_type <"$tf"

	    local name number x
	    while read name number x ; do
		[ "$name" = "number" -a -n "$number" ] && break
	    done <"$sf"
	    if [ -z "$number" ] ; then
		# FIXME: Shouldn't happen.  Fake it?  This is most likely.
		: add_device_ide: faking number
		local channel="${cu%.*}"
		local unit="${cu#*.}"
		number=$(( $channel % 2 * 2 + $unit ))
	    fi

	    local bus_info="ide/${cu}"
	    local yl

	    if add_device_hooks "ide" ; then
		ensure_directory "$device_bus_dir"

	        # This snippet is better than the previous
	        # version. Testing shows it is faster (no forking and
	        # small file) and it avoids a bug/performance issue
	        # substituting in large strings when $LANG is set to
	        # an interesting value.
		local bytes line
		bytes=""
		while read line ; do
		    bytes="${bytes}${line// /}"
		done < "$if"

		# Extract interesting fields.
		# Fields documented in /usr/include/linux/hdreg.h.
		local sn=$(hex2substring "$bytes" 20 20)
		local rm=$(hex2substring "$bytes" 46  8)
		local tm=$(hex2substring "$bytes" 54 40)
	    
		local mf="UNKNOWN"
		case "$tm" in
		    IBM*)      mf="IBM"            ;;
		    QUANTUM*)  mf="Quantum"        ;;
		    ST*)       mf="Seagate"        ;;
		    MATSHITA*) mf="Matshita"       ;;
		    HL-DT-ST*) mf="LG Electronics" ;;
		    LG*)       mf="LG Electronics" ;;
		    TOSHIBA*)  mf="Toshiba"        ;;
		    LTN*)      mf="Lite-On"        ;;
		    AOpen*)    mf="AOpen"          ;;
		    RICOH*)    mf="Ricoh"          ;;
		    NEC*)      mf="NEC"            ;;
		    Maxtor*)   mf="Maxtor"         ;;
		    HTS*)      mf="Hitachi"        ;;
		esac
		
		local ds
		case "$device_type" in
		    disk)  ds="IDE Disk Drive"     ;;
		    cdrom) ds="IDE CD-ROM Drive"   ;;
		    *)     ds="IDE Unknown Device" ;;
		esac

		local cd rl
		vpd_create_hook "$device_bus_dir"
	    fi
	fi
    fi
}

get_kernel_device_name_ide ()
{
    local cu="$1"  # channel.unit

    local x="^\([^ ][^ ]*\)  *${cu}\$"
    sed -n -e "s@${x}@\1@p" "${db_misc_dir}/ide_map"
}
