/* 
 * Mach Operating System
 * Copyright (c) 1993-1989 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 *	File: busses.c
 * 	Author: Alessandro Forin, Carnegie Mellon University
 *	Date:	4/90
 *
 *	Generic autoconfiguration functions,
 *	usable to probe and attach devices
 *	on any bus that suits the generic bus
 *	structure, such as VME, TURBOChannel,
 *	and all the VAX busses.
 *
 */

#include <string.h>
#include <kern/printf.h>
#include <mach/boolean.h>
#include <mach/std_types.h>
#include <chips/busses.h>




/*
 * configure_bus_master
 *
 *	Given the name of a bus_ctlr, look it up in the
 *	init table.  If found, probe it.  If there can be
 *	slaves attached, walk the device's init table
 *	for those that might be attached to this controller.
 *	Call the 'slave' function on each one to see if
 *	ok, then the 'attach' one.
 *
 * Returns 0 if the controller is not there.
 *
 */
boolean_t configure_bus_master(
	const char	*name,
	vm_offset_t	 virt,
	vm_offset_t	 phys,
	int		 adpt_no,
	const char	*bus_name)
{
	struct bus_device *device;
	struct bus_ctlr *master;
	struct bus_driver *driver;

	boolean_t             found = FALSE;

	/*
	 * Match the name in the table, then pick the entry that has the
	 * right adaptor number, or one that has it wildcarded.  Entries
	 * already allocated are marked alive, skip them. 
	 */
	for (master = bus_master_init; master->driver; master++) {
		if (master->alive)
			continue;
		if (((master->adaptor == adpt_no) || (master->adaptor == '?')) &&
		    (strcmp(master->name, name) == 0)) {
			found = TRUE;
			break;
		}
	}

	if (!found)
		return FALSE;

	/*
	 * Found a match, probe it 
	 */
	driver = master->driver;
	if ((*driver->probe) (virt, master) == 0)
		return FALSE;

	master->alive = 1;
	master->adaptor = adpt_no;

	/*
	 * Remember which controller this device is attached to 
	 */
	driver->minfo[master->unit] = master;

	printf("%s%d: at %s%d\n", master->name, master->unit, bus_name, adpt_no);

	/*
	 * Now walk all devices to check those that might be attached to this
	 * controller.  We match the unallocated ones that have the right
	 * controller number, or that have a widcarded controller number. 
	 */
	for (device = bus_device_init; device->driver; device++) {
		int	ctlr;
		if (device->alive || device->driver != driver ||
		    (device->adaptor != '?' && device->adaptor != adpt_no))
			continue;
		ctlr = device->ctlr;
		if (ctlr == '?') device->ctlr = master->unit;
		/*
		 * A matching entry. See if the slave-probing routine is
		 * happy. 
		 */
		if ((device->ctlr != master->unit) ||
		    ((*driver->slave) (device, virt) == 0)) {
			device->ctlr = ctlr;
			continue;
		}

		device->alive = 1;
		device->adaptor = adpt_no;
		device->ctlr = master->unit;

		/*
		 * Save a backpointer to the controller 
		 */
		device->mi = master;

		/*
		 * ..and to the device 
		 */
		driver->dinfo[device->unit] = device;

		if (device->slave >= 0)
			printf(" %s%d: at %s%d slave %d",
			       device->name, device->unit,
			       driver->mname, master->unit, device->slave);
		else
			printf(" %s%d: at %s%d",
			       device->name, device->unit,
			       driver->mname, master->unit);

		/*
		 * Now attach this slave 
		 */
		(*driver->attach) (device);
		printf("\n");
	}
	return TRUE;
}

/*
 * configure_bus_device
 *
 *	Given the name of a bus_device, look it up in the
 *	init table.  If found, probe it.  If it is present,
 *	call the driver's 'attach' function.
 *
 * Returns 0 if the device is not there.
 *
 */
boolean_t configure_bus_device( 
	const char	*name,
	vm_offset_t	 virt,
	vm_offset_t	 phys,
	int 		 adpt_no,
	const char	*bus_name)
{
	struct bus_device *device;
	struct bus_driver *driver;

	boolean_t             found = FALSE;

	/*
	 * Walk all devices to find one with the right name
	 * and adaptor number (or wildcard).  The entry should
	 * be unallocated, and also the slave number should
	 * be wildcarded.
	 */
	for (device = bus_device_init; device->driver; device++) {
		if (device->alive)
			continue;
		if (((device->adaptor == adpt_no) || (device->adaptor == '?')) &&
		    (device->slave == -1) &&
		    ((!device->phys_address) ||
		     ((device->phys_address == phys) && (device->address == virt))) &&
		    (strcmp(device->name, name) == 0)) {
			found = TRUE;
			break;
		}
	}

	if (!found)
		return FALSE;

	/*
	 * Found an entry, probe the device
	 */
	driver = device->driver;
	if ((*driver->probe) (virt, (struct bus_ctlr *)device) == 0)
		return FALSE;

	device->alive = 1;
	device->adaptor = adpt_no;

	printf("%s%d: at %s%d", device->name, device->unit, bus_name, adpt_no);

	/*
	 * Remember which driver this device is attached to 
	 */
	driver->dinfo[device->unit] = device;

	/*
	 * Attach the device
	 */
	(*driver->attach) (device);
	printf("\n");

	return TRUE;
}

