# -*- shell-script -*-

# 33adapter_dt_nosysfs - Device-tree only adapter code.

# This file is part of the Linux lsvpd package.

# (C) Copyright IBM Corp. 2002, 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: 33adapter_dt_nosysfs,v 1.4 2005/05/13 06:31:39 martins Exp $

[ -n "$source_device_tree" -a -z "$sysfs_dir" ] || return 0

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

make_multiplexed dt_list_adapters_setup
make_multiplexed dt_adapter_crosslink

list_adapters ()
{
    # Sets: adapter_list
    adapter_list=""

    local types="scsi ethernet ide usb display serial"
    local t
    for t in $types ; do
	list_adapters_of_type "$t"
    done
}

list_adapters_of_type ()
{
    # Sets: adapter_list

    local type="$1"

    # Could do a single find for all adapter types (in
    # db_initialise_bus) and create a map, but BusyBox's find doesn't
    # support "-o", so we might as well do a find per type in this
    # function.
    local n bus_info subdir dt_adapter_types dt_type

    dt_list_adapters_setup "$type"

    get_dt_adapter_types "$type"

    for dt_type in $dt_adapter_types ; do
	for n in $(find "${source_device_tree}" -name "${dt_type}@*") ; do
	    local bus_info=""
	    dt_set_bus_info_hook "$n"
	    if [ -n "$bus_info" ] ; then
		local relnode="${db_bus_dt_subdir}/${n#${source_device_tree}/}"
		bus_alias_set "$bus_info" "$relnode"
		# Has channel?  Also alias without channel.
		case "$bus_info" in
		    */*/*)
			local pbi="${bus_info%/*}"
			if bus_alias_set "$pbi" "${relnode%/*}" ; then
			    dt_adapter_crosslink "$type" "$pbi" 
			    adapter_list="${adapter_list} ${type}@${pbi}"
			fi
			;;
		esac

		dt_adapter_crosslink "$type" "$bus_info" "$n"
		adapter_list="${adapter_list} ${type}@${bus_info}"
	    else
		debug "list_adapters: failed to get bus_info for \"${n}\""
	    fi
	done
    done
}

#---------------------------------------------------------------------

# Bus alias is set in list_adapters_of_type (in dt_adapter_crosslink).
set_adapter_bus_dir ()
{
    local type="$1"
    local bus_info="$2"

    local bus_alias
    bus_alias_get "$bus_info"
    adapter_bus_dir="$bus_alias"
}

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

dt_set_bus_info_hook ()
{
    local node="$1"

    local bus_type dom bus dev fun channel

    # Sanity check to ensure the loop below will terminate.
    [ "${node#${source_device_tree}}" = "$node" ] && return

    # Get property name for PCI domain on IBM pSeries big-bus-num machines.
    [ -z "$dt_pci_domain_prop" ] && set_dt_pci_domain_prop_hook

    local d="$node"

    while [ "$d" != "$source_device_tree" ] ; do
	local device_type=""
	[ -f "${d}/device_type" ] && read device_type <"${d}/device_type"

	case "$device_type" in
	    pci|ht)
	        # The range bottom of the 1st PCI bus-range we hit is the bus#.
		if [ -z "$bus" ] ; then
		    set -- $(tdump "${d}/bus-range")
		    bus_type="pci"
		    bus="$4"
		fi
		
	        # Found a PCI domain property: remember it & we're done!
		if [ -n "$dt_pci_domain_prop" -a \
		    -f "${d}/${dt_pci_domain_prop}" ] ; then
		    dom=$(tdump "${d}/${dt_pci_domain_prop}")
		    dom="${dom// /}"
		    break
		fi
		;;
	    vdevice|isa)
		bus_type="$device_type"
		break
		;;
	    *)
	        # Channel possibly only in original basename.
		[ -z "$channel" ] && channel="$dev"
		
	        # Adapter node?  Put dev[,fun] into $dev. 
		local bn="${d##*/}" # basename
		dev="${bn#*@}"
		;;	    
	esac

	d="${d%/*}" # dirname
    done

    local result

    case "$bus_type" in
	pci)
	    if [ -n "$bus" -a -n "$dev" ] ; then
		[ -n "$dom" ] || dom=0
		
		fun=0
		case "$dev" in
		    # Note: order is important here.  :-)
		    (*,*) fun="${dev#*,}" ; dev="${dev%,*}" ;;
		esac
		
		result=$(printf "%04x:%02x:%02x.%x" \
		    "0x${dom}" "0x${bus}" "0x${dev}" "0x${fun}")
		
		[ -n "$channel" ] && result="${result}/${channel}"
	    fi
	    ;;
	vdevice|isa)
	    result="$dev"
	    ;;
    esac

    [ -n "$bus_type" -a -n "$result" ] && \
	bus_info="${bus_type}/${result}"
}
