# -*- 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, 2005

# 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.30 2005/02/22 22:44:40 martins Exp $

[ -f "/proc/ide/drivers" ] || 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_functions="${list_devices_functions} proc_list_devices_ide"

proc_list_devices_ide ()
{
    # Sets: device_list

    device_setup_ide

    local device_name bus_addr
    while read device_name bus_addr ; do
	device_list="${device_list} ide/${bus_addr}"
    done <"${db_misc_dir}/ide_map"
}

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

    local device_name
    get_kernel_device_name "ide" "$cu"
    local name="${device_name##*/}" # basename

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

    if [ -d "$d" ] ; then
	local if="${d}/identify"
	local tf="${d}/media"
	local sf="${d}/settings"

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

	    local adapter device_type
	    if cd -P "$d" ; then
		adapter="${PWD%/*}" # dirname
		adapter="${adapter##*/}" # basename
		cd "$OLDPWD"
	    fi
	    read device_type <"$tf"

	    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"        ;;
		    PIONEER*)  mf="Pioneer"        ;;
		esac
		
		local ds
		case "$device_type" in
		    disk)   ds="IDE Disk Drive"     ;;
		    cdrom)  ds="IDE CD-ROM Drive"   ;;
		    tape)   ds="IDE Tape Drive"     ;;
		    floppy) ds="IDE Floppy Drive"   ;;
		    *)      ds="IDE Unknown Device" ;;
		esac

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

get_kernel_device_name_ide ()
{
    # Sets: device_name

    local cu="$1"  # channel.unit

    local bus_addr
    while read device_name bus_addr ; do
	[ "$bus_addr" = "$cu" ] && return
    done <"${db_misc_dir}/ide_map"
    device_name=""
}
