/*	$OpenBSD: if_le.c,v 1.4 2014/08/21 14:24:08 mpi Exp $	*/
/* $NetBSD: if_le.c,v 1.3 2013/01/22 15:48:40 tsutsui Exp $ */

/*
 * Copyright (c) 2013 Izumi Tsutsui.  All rights reserved.
 * Copyright (c) 2003 Tetsuya Isaki. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/*
 * Copyright (c) 1982, 1990, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * from: hp300/dev/if_le.c      7.16 (Berkeley) 3/11/93
 *
 *      @(#)if_le.c     8.1 (Berkeley) 6/10/93
 */

#include <sys/param.h>

#include <netinet/in.h>

#include <luna88k/stand/boot/samachdep.h>
#include <machine/board.h>
#include <lib/libsa/net.h>
#include <lib/libsa/netif.h>

/* libsa netif_driver glue functions */
static int  le_match(struct netif *, void *);
static int  le_probe(struct netif *, void *);
static void le_init(struct iodesc *, void *);
static int  le_get(struct iodesc *, void *, size_t, time_t);
static int  le_put(struct iodesc *, void *, size_t);
static void le_end(struct netif *);

static void myetheraddr(uint8_t *);

/* libsa netif glue stuff */
struct netif_stats le_stats;
struct netif_dif le_ifs[] = {
	{ 0, 1, &le_stats, 0, 0, },
};

struct netif_driver le_netif_driver = {
	"le",
	le_match,
	le_probe,
	le_init,
	le_get,
	le_put,
	le_end,
	le_ifs,
	sizeof(le_ifs) / sizeof(le_ifs[0]),
};

int
leinit(void)
{
	void *cookie;
	void *reg, *mem;
	uint8_t eaddr[6];

	reg = (void *)LANCE_ADDR;
	mem = (void *)(TRI_PORT_RAM + 0x010000);	/* XXX */

	if (badaddr(reg, 4) != 0)
		return 0;

	myetheraddr(eaddr);

	cookie = lance_attach(0, reg, mem, eaddr);
	if (cookie == NULL)
		return 0;

	printf("le0: Ethernet address %s\n", ether_sprintf(eaddr));

	return 1;
}

static int
le_match(struct netif *nif, void *machdep_hint)
{
	void *cookie;
	uint8_t *eaddr;

	/* XXX should check nif_unit and unit number in machdep_hint path */

	cookie = lance_cookie(nif->nif_unit);
	if (cookie == NULL && nif->nif_unit == 0 && leinit() != 0)
		cookie = lance_cookie(nif->nif_unit);
	if (cookie == NULL)
		return 0;

	eaddr = lance_eaddr(cookie);
	if (eaddr == NULL)
		return 0;

	return 1;
}

static int
le_probe(struct netif *nif, void *machdep_hint)
{

	/* XXX what should be checked? */

	return 0;
}

static void
le_init(struct iodesc *desc, void *machdep_hint)
{
	struct netif *nif = desc->io_netif;
	struct netif_dif *dif = &nif->nif_driver->netif_ifs[nif->nif_unit];
	void *cookie;
	uint8_t *eaddr;

#ifdef DEBUG
	printf("%s\n", __func__);
#endif

	cookie = lance_cookie(nif->nif_unit);
	eaddr = lance_eaddr(cookie);

	lance_init(cookie);

	/* fill glue stuff */
	dif->dif_private = cookie;
	memcpy(desc->myea, eaddr, 6);
}

static int
le_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout)
{
	struct netif *nif = desc->io_netif;
	struct netif_dif *dif = &nif->nif_driver->netif_ifs[nif->nif_unit];
	void *cookie = dif->dif_private;
	int len = -1;
	time_t t;

	t = getsecs() + timeout;
	while (getsecs() < t) {
		len = lance_get(cookie, pkt, len);
		if (len > 0)
			break;
	}

	return len;
}

static int
le_put(struct iodesc *desc, void *pkt, size_t len)
{
	struct netif *nif = desc->io_netif;
	struct netif_dif *dif = &nif->nif_driver->netif_ifs[nif->nif_unit];
	void *cookie = dif->dif_private;
#ifdef DEBUG
 	struct ether_header *eh;

 	eh = pkt;
 	printf("dst:  %s\n", ether_sprintf(eh->ether_dhost));
 	printf("src:  %s\n", ether_sprintf(eh->ether_shost));
 	printf("type: 0x%x\n", eh->ether_type & 0xffff);
#endif

	return lance_put(cookie, pkt, len) ? len : -1;
}

static void
le_end(struct netif *nif)
{
	struct netif_dif *dif = &nif->nif_driver->netif_ifs[nif->nif_unit];
	void *cookie = dif->dif_private;

#ifdef DEBUG
	printf("%s\n", __func__);
#endif
	lance_end(cookie);
}

static void
myetheraddr(uint8_t *ether)
{
	unsigned int i, loc;
	volatile struct { uint32_t ctl; } *ds1220;

	switch (machtype) {
	case LUNA_88K:
		/*
		 * fuse_rom_data[] begins with "ENADDR=00000Axxxxxx"
		 */
		loc = 7;
		for (i = 0; i < 6; i++) {
			int u, l;

			u = fuse_rom_data[loc];
			u = (u < 'A') ? u & 0xf : u - 'A' + 10;
			l = fuse_rom_data[loc + 1];
			l = (l < 'A') ? l & 0xf : l - 'A' + 10;

			ether[i] = l | (u << 4);
			loc += 2;
		}
		break;
	case LUNA_88K2:
		ds1220 = (void *)(LANCE_ADDR + 8);
		loc = 12;
		for (i = 0; i < 6; i++) {
			unsigned int u, l, hex;

			ds1220->ctl = (loc) << 16;
			u = 0xf0 & (ds1220->ctl >> 12);
			ds1220->ctl = (loc + 1) << 16;
			l = 0x0f & (ds1220->ctl >> 16);
			hex = (u < '9') ? l : l + 9;

			ds1220->ctl = (loc + 2) << 16;
			u = 0xf0 & (ds1220->ctl >> 12);
			ds1220->ctl = (loc + 3) << 16;
			l = 0x0f & (ds1220->ctl >> 16);

			ether[i] = ((u < '9') ? l : l + 9) | (hex << 4);
			loc += 4;
		}
		break;
	default:
		ether[0] = 0x00; ether[1] = 0x00; ether[2] = 0x0a;
		ether[3] = 0xDE; ether[4] = 0xAD; ether[5] = 0x00;
		break;
	}
}
