/*
 * Copyright (C) 2003-2013 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#ifdef STATE

struct {
	uint16_t reg[32];
	int active;
} NAME;

#endif /* STATE */

#ifdef BEHAVIOR

static void
NAME_(reg_write)(struct cpssp *cpssp, unsigned int reg, uint16_t val)
{
	/*
	 * Write
	 */
	uint16_t wmask;

	switch (reg) {
	case  0: wmask = 0x7dffUL; break;
	case  4: wmask = 0xa3ffUL; break;
	case 16: wmask = 0xf000UL; break;
	default: wmask = 0x0000UL; break;
	};
	cpssp->NAME.reg[reg] &= ~wmask;
	cpssp->NAME.reg[reg] |= val & wmask;
}

static void
NAME_(reg_read)(struct cpssp *cpssp, unsigned int reg, uint16_t *valp)
{
	*valp = cpssp->NAME.reg[reg];

	if (19 <= reg
	 && reg <= 25) {
		/* Register is self clearing. */
		cpssp->NAME.reg[reg] = 0;
	}
}

static void
NAME_(recv_from_net)(
	void *_cpssp,
	const void *buf,
	unsigned int buflen
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	if (! cpssp->state_power) {
		return;
	}

	cpssp->NAME.active = 1;

	if (cpssp->NAME.reg[0] & 0x4000) {
		/* Loopback Mode */
		/* Drop message. */
	} else {
		NAME_(recv_from_phy)(cpssp, buf, buflen);
	}
}

static void
NAME_(recv_from_controller)(
	struct cpssp *cpssp,
	const void *buf,
	unsigned int buflen
)
{
	if (! cpssp->state_power) {
		return;
	}

	cpssp->NAME.active = 1;

	if (cpssp->NAME.reg[0] & 0x4000) {
		/* Loopback Mode */
		NAME_(recv_from_phy)(cpssp, buf, buflen);
	} else {
		sig_eth_send(cpssp->port_eth, cpssp, buf, buflen);
	}
}

static void
NAME_(tick)(void *_cpssp)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;
	int active;

	active = cpssp->NAME.active;
	cpssp->NAME.active = 0;

	sig_boolean_set(cpssp->port_busy, cpssp, active);

	time_call_after(TIME_HZ / 2, NAME_(tick), cpssp);
}

/*
 * The following function resets the cards MDI registers to their poweron
 * state. It tries to fill them with realistic values, i.e. values a real
 * card would have.
 * FIXME fox: fill all, not just selected
 */
static void
NAME_(reset)(struct cpssp *cpssp)
{
	cpssp->NAME.reg[ 0] = 0x3100;	/* Status Register 0 */
	cpssp->NAME.reg[ 1] = 0x782d;	/* Status Register 1 */
	cpssp->NAME.reg[ 2] = 0x02A8;	/* MDI Identification Register 2 */
	cpssp->NAME.reg[ 3] = 0x0154;	/* MDI Identification Register 3 */
	cpssp->NAME.reg[ 4] = 0x41e1;	/* Auto Negotiation Advertisement */
					/* Register 4 */
	cpssp->NAME.reg[ 5] = 0x41e1;	/* Auto Negotiation Link Partner */
					/* Ability Register 5 */
	cpssp->NAME.reg[ 6] = 0x0003;	/* Auto Negotiation Expansion */
					/* Register 6 */
	cpssp->NAME.reg[16] = 0x0003;	/* Status and Control Register 16 */
	cpssp->NAME.reg[18] = 0x0000	/* Clock Synthesis */
					/* and Control Register 18 */
				| 1;	/* Phy Address */
}

static void
NAME_(create)(struct cpssp *cpssp)
{
	time_call_after(TIME_HZ / 2, NAME_(tick), cpssp);
}

static void
NAME_(destroy)(struct cpssp *cpssp)
{
}

#endif /* BEHAVIOR */
