/*
 *
 */

#include <ppcboot.h>
#include <command.h>
#include "net.h"

#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)

extern int eepro100_initialize(bd_t*);
extern int dc21x4x_initialize(bd_t*);

static struct eth_device *eth_devices, *eth_current;

int eth_register(struct eth_device* dev)
{
	struct eth_device *d;

	if (!eth_devices)
		eth_current = eth_devices = dev;
	else {
		for (d=eth_devices; d->next!=eth_devices; d=d->next);
		d->next = dev;
	}

	dev->state = ETH_STATE_INIT;
	dev->next  = eth_devices;

	return 0;
}

int eth_initialize(bd_t *bis)
{
	int eth_number = 0;

	eth_devices = NULL;
	eth_current = NULL;

#ifdef CONFIG_EEPRO100
	eepro100_initialize(bis);
#endif
#ifdef CONFIG_TULIP
	dc21x4x_initialize(bis);
#endif

	if (!eth_devices)
		printf("No ethernet found.\n");

	else {
		struct eth_device *dev = eth_devices;

		do {
			if (eth_number++)
				printf(", ");
			printf("%s", dev->name);
			dev = dev->next;
		} while(dev != eth_devices);

		printf("\n");
	}

	return eth_number;
}

int eth_init(bd_t *bis)
{
	struct eth_device* old_current;

	if (!eth_current)
		return 0;

	old_current = eth_current;
	do {
#ifdef DEBUG
		printf("Trying %s\n", eth_current->name);
#endif

		if (eth_current->init(eth_current, bis)) {
			eth_current->state = ETH_STATE_ACTIVE;

			return 1;
		}

#ifdef DEBUG
		printf("FAIL\n");
#endif

		eth_try_another();
	} while (old_current != eth_current);

	return 0;
}

void eth_halt(void)
{
	if (!eth_current)
		return;

	eth_current->halt(eth_current);

	eth_current->state = ETH_STATE_PASSIVE;
}

int eth_send(volatile void *packet, int length)
{
	if (!eth_current)
		return -1;

	return eth_current->send(eth_current, packet, length);
}

int eth_rx(void)
{
	if (!eth_current)
		return -1;

	return eth_current->recv(eth_current);
}

void eth_try_another(void)
{
	if (!eth_current)
		return;

	eth_current = eth_current->next;
}

#endif
