socket and when it connects allocate another one. That means we need to
use to break the 1:1 mapping between wiznet and OS socket numbering
- handle address collision interrupt
+ - rework disconnect state machine
*/
+#include <kernel.h>
+#include <kdata.h>
+#include <netdev.h>
+#include <net_wiznet.h>
+#include <printf.h>
+
+#ifdef CONFIG_NET_WIZNET
+
static uint8_t irqmask;
-#define RX_MASK 0x1FFF
-#define TX_MASK 0x1FFF
+#define RX_MASK 0x07FF
+#define TX_MASK 0x07FF
+
+#define MR 0x0000
+#define MR_RESET 0x80
+#define MR_PB 0x10
+#define MR_PPPOE 0x08
+#define MR_AUTOINC 0x02
+#define MR_INDIRECT 0x01
+
+#define GAR0 0x0001
+#define SUBR0 0x0005
+#define SHAR0 0x0009
+#define SIPR0 0x000F
+#define IR 0x0015
+#define IMR 0x0016
+#define RTR0 0x0017
+#define RCR 0x0019
+#define RMSR 0x001A
+#define TMSR 0x001B
+#define PATR0 0x001C
+#define PTIMER 0x0028
+#define PMAGIC 0x0029
+#define UIPR0 0x002A
+#define UPORT0 0x002E
+
+#define Sn_MR 0x0400
+#define Sn_CR 0x0401
+#define OPEN 0x01
+#define LISTEN 0x02
+#define CONNECT 0x04
+#define DISCON 0x08
+#define CLOSE 0x10
+#define SEND 0x20
+#define SEND_MAC 0x21
+#define SEND_KEEP 0x22
+#define RECV 0x40
+#define Sn_IR 0x0402
+#define I_SEND_OK 0x10
+#define I_TIMEOUT 0x08
+#define I_RECV 0x04
+#define I_DISCON 0x02
+#define I_CON 0x01
+#define Sn_SR 0x0403
+#define SOCK_CLOSED 0x00
+#define SOCK_ARP 0x01
+#define SOCK_INIT 0x13
+#define SOCK_LISTEN 0x14
+#define SOCK_SYNSENT 0x15
+#define SOCK_SYNRECV 0x16
+#define SOCK_ESTABLISHED 0x17
+#define SOCK_FIN_WAIT 0x18
+#define SOCK_CLOSING 0x1A
+#define SOCK_TIME_WAIT 0x1B
+#define SOCK_CLOSE_WAIT 0x1C
+#define SOCK_LAST_ACK 0x1D
+#define SOCK_UDP 0x22
+#define SOCK_IPRAW 0x32
+#define SOCK_MACROW 0x42
+#define SOC_PPPOE 0x5F
+#define Sn_PORT0 0x0404
+#define Sn_DHAR0 0x0406
+#define Sn_DIPR0 0x040C
+#define Sn_DPORT0 0x0410
+#define Sn_MSSR0 0x0412
+#define Sn_PROTO 0x0414
+#define Sn_TOS 0x0415
+#define Sn_TTL 0x0416
+#define Sn_TX_FSR 0x0420
+#define Sn_TX_RD0 0x0422
+#define Sn_TX_WR0 0x0424
+#define Sn_RX_RSR 0x0426
+#define Sn_RX_RD0 0x0428
+
+
+
/* Core helpers: platform supplies wiz_bread{_u} and wiz_bwrite{_u} */
-/* Might be worth inlining these on some platforms - need to think about
- that carefully */
+__sfr __at 0x28 mr;
+__sfr __at 0x29 idm_ar0;
+__sfr __at 0x2A idm_ar1;
+__sfr __at 0x2B idm_dr;
-static uint8_t wiz_readb(uint16_t offset)
+/* We assume indirect, autoinc is always set */
+static uint8_t wiz_readb(uint16_t off)
{
- uint8_t n;
- wiz_bread(offset, &n, 1);
- return n;
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ return idm_dr;
}
-static uint16_t wiz_readw(uint16_t offset)
+static uint16_t wiz_readw(uint16_t off)
{
uint16_t n;
- wiz_bread(offset, &n, 2);
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ n = ((uint16_t)idm_dr) << 8;
+ n |= idm_dr;
return n;
}
-static uint32_t wiz_readl(uint16_t offset)
+static uint32_t wiz_readl(uint16_t off)
{
uint32_t n;
- wiz_bread(offset, &n, 4);
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ n = ((uint32_t)idm_dr) << 24;
+ n |= ((uint32_t)idm_dr) << 16;
+ n |= ((uint16_t)idm_dr) << 8;
+ n |= idm_dr;
return n;
}
-static void wiz_writeb(uint16_t offset, uint8_t n)
+static void wiz_bread(uint16_t off, uint8_t *p, uint8_t n)
{
- wiz_bwrite(offset, &n, 1);
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ while(n--)
+ *p++ = idm_dr;
}
-static void wiz_writew(uint16_t offset, uint16_t n)
+static void wiz_breadu(uint16_t off, uint8_t *p, uint8_t n)
{
- wiz_bwrite(offset, &n, 2);
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ while(n--)
+ uputc(idm_dr, p++);
}
-#ifdef BIG_ENDIAN
-#define wiz_writew_n(a,b) wiz_writew(a,b)
-#define wiz_readw_n(a) wiz_readw(a)
-#else
+static void wiz_writeb(uint16_t off, uint8_t n)
+{
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ idm_dr = n;
+}
-static void wiz_writew_n(uint16_t offset, uint16_t n)
+static void wiz_writew(uint16_t off, uint16_t n)
{
- n = htons(n);
- wiz_bwrite(offset, &n, 2);
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ idm_dr = n >> 8;
+ idm_dr = n;
}
-static uint16_t wiz_readw_n(uint16_t offset)
+static void wiz_writel(uint16_t off, uint32_t n)
{
- uint16_t n;
- wiz_bread(offset, &n, 2);
- return ntohs(n);
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ idm_dr = n >> 24;
+ idm_dr = n >> 16;
+ idm_dr = n >> 8;
+ idm_dr = n;
}
-#endif
+static void wiz_bwrite(uint16_t off, uint8_t *p, uint8_t n)
+{
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ while(n--)
+ idm_dr = *p++;
+}
+
+static void wiz_bwriteu(uint16_t off, uint8_t *p, uint8_t n)
+{
+ idm_ar0 = off >> 8;
+ idm_ar1 = off;
+ while(n--)
+ idm_dr = ugetc(p++);
+}
/* FIXME: look for ways to fold these four together */
static void wiz_queue(uint16_t i, uint16_t n, uint8_t * p)
{
uint16_t dm = wiz_readw(Sn_TX_WR0 + i) & TX_MASK;
- uint16_t tx_base = 0x8000 + (i << 3); /* i is already << 8 */
+ uint16_t tx_base = 0x4000 + (i << 3); /* i is already << 8 */
if (dm + n >= TX_MASK) {
uint16_t us = TX_MASK + 1 - dm;
static void wiz_queue_u(uint16_t i, uint16_t n, uint8_t * p)
{
- uint16_t dm = wiz_readw_n(Sn_TX_WR0 + i) & TX_MASK;
- uint16_t tx_base = 0x8000 + (i << 3); /* i is already << 8 */
+ uint16_t dm = wiz_readw(Sn_TX_WR0 + i) & TX_MASK;
+ uint16_t tx_base = 0x4000 + (i << 3); /* i is already << 8 */
if (dm + n >= TX_MASK) {
uint16_t us = TX_MASK + 1 - dm;
- wiz_bwrite_u(dm + tx_base, p, us);
- wiz_bwrite_u(tx_base, p + us, n - us);
+ wiz_bwriteu(dm + tx_base, p, us);
+ wiz_bwriteu(tx_base, p + us, n - us);
} else
- wiz_bwrite_u(dm + tx_base, p, n);
+ wiz_bwriteu(dm + tx_base, p, n);
}
static void wiz_dequeue(uint16_t i, uint16_t n, uint8_t * p)
{
- uint16_t dm = wiz_readw_n(Sn_RX0 + i) & RX_MASK;
- uint16_t rx_base = 0xC000 + (i << 3); /* i is already << 8 */
+ uint16_t dm = wiz_readw(Sn_RX_RD0 + i) & RX_MASK;
+ uint16_t rx_base = 0x6000 + (i << 3); /* i is already << 8 */
if (dm + n >= RX_MASK) {
uint16_t us = RX_MASK + 1 - dm;
static void wiz_dequeue_u(uint16_t i, uint16_t n, uint8_t * p)
{
- uint16_t dm = wiz_readw_n(Sn_RX0 + i) & RX_MASK;
- uint16_t rx_base = 0xC000 + (i << 3); /* i is already << 8 */
+ uint16_t dm = wiz_readw(Sn_RX_RD0 + i) & RX_MASK;
+ uint16_t rx_base = 0x6000 + (i << 3); /* i is already << 8 */
if (dm + n >= RX_MASK) {
uint16_t us = RX_MASK + 1 - dm;
- wiz_bread_u(dm + rx_base, p, us);
- wiz_bread_u(rx_base, p + us, n - us);
+ wiz_breadu(dm + rx_base, p, us);
+ wiz_breadu(rx_base, p + us, n - us);
} else
- wiz_bread_u(dm + rx_base, p, n);
+ wiz_breadu(dm + rx_base, p, n);
}
static void wiz_wakeall(struct socket *s)
/*
* Process interrupts from the WizNet device
*/
-void wiz_event_s(uint8_t i)
+static void wiz_event_s(uint8_t i)
{
struct socket *s = &sockets[i];
uint16_t stat = wiz_readw(Sn_IR + (i << 8)); /* BE read of reg pair */
- if (stat & 0x800) {
+ if (stat & 0x1000) {
/* Transmit completed: window re-open. We can allow more
data to flow from the user */
s->s_iflag &= ~SI_THROTTLE;
- wiz_writeb(Sn_IR + (i << 8), 0x08); /* Clear the flag down */
+ wiz_writeb(Sn_IR + (i << 8), 0x10); /* Clear the flag down */
wakeup(&s->s_data);
}
+ if (stat & 0x800) {
+ /* Timeout */
+ s->s_error = ETIMEDOUT;
+ wiz_writeb(Sn_CR + (i << 8), CLOSE);
+ wiz_wakeall(s);
+ wiz_writeb(Sn_IR + (i << 8), 0x08);
+ wiz_eof(s);
+ /* Fall through and let CLOSE state processing do the work */
+ }
if (stat & 0x400) {
/* Receive wake: Poke the user in case they are reading */
s->s_iflag |= SI_DATA;
if (stat & 0x200) {
/* Disconnect: Just kill our host socket. Not clear if this
is right or we need to drain data first */
- s->state = SS_CLOSED;
+ wiz_writeb(Sn_IR + (i << 8), 0x02); /* Clear the flag down */
+ wiz_writeb(Sn_CR + (i << 8), CLOSE);
wiz_eof(s);
+ /* When we fall through we'll see CLOSE state and do the
+ actual shutting down */
}
if (stat & 0x100) {
/* Connect: Move into connected state */
s->s_state = SS_CONNECTED;
wakeup(s);
}
+ wiz_writeb(Sn_IR + (i << 8), 0x01); /* Clear the flag down */
}
/* ??? return if high bits set here ?? */
switch (stat & 0xFF) {
case 0: /* SOCK_CLOSED */
if (s->s_state != SS_CLOSED && s->s_state != SS_UNUSED) {
- s->s_state = SS_CLOSED;
- if (s->s_state != SS_CLOSING) {
+ if (s->s_state != SS_CLOSING && s->s_state != SS_DEAD) {
s->s_error = ECONNRESET; /* Sort of a guess */
wiz_wakeall(s);
} else
wakeup(s);
+ irqmask &= ~(1 << i);
+ wiz_writeb(IMR, irqmask);
+ wiz_eof(s);
+ /* Net layer wants us to burn the socket */
+ if (s->s_state == SS_DEAD)
+ sock_closed(s);
+ else /* so net_close() burns the socket */
+ s->s_state = SS_CLOSED;
}
- irqmask &= ~(1 << i);
- wiz_writeb(Sn_IMR, irqmask);
break;
case 0x13: /* SOCK_INIT */
break;
if (s->s_state == SS_CONNECTING) {
s->s_state == SS_CONNECTED;
wakeup(s);
- } else if (s->s_state == SS_LISTEN) {
+ } else if (s->s_state == SS_LISTENING) {
/* TODO: We actually have to split the association between
wiznet and host sockets as we have multiple wiznet sockets
in the accept queue and a listener that is not really a
case 0x1C: /* SOCK_CLOSE_WAIT */
if (s->s_state == SS_CONNECTED
|| s->s_state == SS_CONNECTING)
- s->s_state == SS_CLOSEWAIT;
+ s->s_state = SS_CLOSEWAIT;
wiz_eof(s);
if (s->s_state == SS_ACCEPTWAIT) {
/* HUM ??? */
{
uint8_t irq;
uint8_t i = 0;
+ struct socket *s = sockets;
/* Polling cases */
- irq = wiz_readb(IR2);
+ irq = wiz_readb(IR) & 0x0F;
if (irq == 0)
return;
{
uint16_t i = s - sockets;
uint8_t r = SOCK_INIT;
+ uint16_t off = i << 8;
- switch (s->sock_type) {
+ switch (s->s_type) {
case SOCKTYPE_TCP:
- wiz_writeb(Sn_MR + (i << 8), 0x01); /* TCP */
- wiz_writew(Sn_PORT0 + (i << 8), s->s_addr[SADDR_SRC].port);
+ wiz_writeb(Sn_MR + off, 0x21); /* TCP, delayed ack */
+ /* We keep ports net endian so don't byte swap */
+ wiz_bwrite(Sn_PORT0 + off, &s->s_addr[SADDR_SRC].port, 2);
break;
case SOCKTYPE_UDP:
- wiz_writeb(Sn_MR + (i << 8), 0x02); /* UDP */
- wiz_writew(Sn_PORT0 + (i << 8), s->s_addr[SADDR_SRC].port);
+ wiz_writeb(Sn_MR + off, 0x02); /* UDP */
+ wiz_bwrite(Sn_PORT0 + off, &s->s_addr[SADDR_SRC].port, 2);
r = SOCK_UDP;
break;
case SOCKTYPE_RAW:
- wiz_writeb(Sn_PROTO + (i << 8), s->s_addr[ADDR_SRC].port); /* hack */
- wiz_writeb(Sn_MR + (i << 8), 0x03); /* RAW */
+ wiz_writeb(Sn_PROTO + off, s->s_addr[SADDR_SRC].port); /* hack */
+ wiz_writeb(Sn_MR + off, 0x03); /* RAW */
r = SOCK_IPRAW;
}
- wiz_writeb(Sn_CR + (i << 8), OPEN);
+ /* Make an open request to open the socket */
+ wiz_writeb(Sn_CR + off, OPEN);
- if (wiz_readb(Sn_SR + (i << 8)) != r) {
+ /* If the reply is not immediately SOCK_INT we failed */
+ if (wiz_readb(Sn_SR + off) != r) {
udata.u_error = EADDRINUSE; /* Something broke ? */
return -1;
}
+ /* Interrupt on if available mark as bound */
irqmask |= 1 << i;
- wiz_writeb(Sn_IMR, irqmask);
+ wiz_writeb(IMR, irqmask);
s->s_state = SS_BOUND;
/* Do we need to delay the SS_BOUND until the chip interrupts ? */
return 0;
i <<= 8;
+ /* Issue a listen command. Check the state went to SOCK_LISTEN */
wiz_writeb(Sn_CR + i, LISTEN);
if (wiz_readb(Sn_SR + i) != SOCK_LISTEN) {
- udata.u_error = EPROTO; /* ??? */
+ udata.u_error = EIO;//FIXME EPROTO; /* ??? */
return -1;
}
s->s_state = SS_LISTENING;
uint16_t i;
i = s - sockets;
i <<= 8;
- wiz_writel(Sn_DIRP0 + i, s->s_addr[SADDR_DST].addr);
- wiz_writew(Sn_DPORT0 + i, s->s_addr[SADDR_DST].port);
- wiz_writeb(Sn_NR + i, CONNECT);
+ /* Already net endian */
+ wiz_bwrite(Sn_DIPR0 + i, &s->s_addr[SADDR_DST].addr, 4);
+ wiz_bwrite(Sn_DPORT0 + i, &s->s_addr[SADDR_DST].port, 2);
+ wiz_writeb(Sn_CR + i, CONNECT);
s->s_state = SS_CONNECTING;
} else {
/* UDP/RAW - note have to do our own filtering for 'connect' */
void net_close(struct socket *s)
{
uint16_t i = s - sockets;
+ uint16_t off = i << 8;
- if (s->s_type == SOCKTYPE_TCP) {
- wiz_writeb(Sn_CR + (i << 8), DISCON);
+ if (s->s_type == SOCKTYPE_TCP && s->s_state != SS_CLOSED) {
+ wiz_writeb(Sn_CR + off, DISCON);
s->s_state = SS_CLOSING;
} else {
- wiz_clear_int(i);
- wiz_writeb(Sn_CR + (i << 8), CLOSE);
- s->s_state = SS_UNINIT;
+ irqmask &= ~(1 << i);
+ wiz_writeb(IMR, irqmask);
+ wiz_writeb(Sn_CR + off, CLOSE);
+ sock_closed(s);
}
}
arg_t net_read(struct socket *s, uint8_t flag)
{
- uint16_t n;
+ uint16_t n = 0xFFFF;
uint16_t r;
uint16_t i = s - sockets;
+ uint8_t st;
i <<= 8;
+ s->s_iflag &= ~SI_DATA;
+
/* FIXME: IRQ protection */
/* Wait for data - push int core code ? */
while ((s->s_iflag & SI_DATA) == 0) {
/* Check for an EOF (covers post close cases too) */
if (s->s_iflag & SI_EOF)
return 0;
- /* Needs irq protection */
- if (psleep_flags(&s->iflag, flag))
- return -1;
/* Keep waiting until we get the right state */
/* Bytes available */
- n = wiz_readw_n(Sn_RX_RSR + i);
- if (n)
+ n = wiz_readw(Sn_RX_RSR + i);
+ if (n) {
s->s_iflag |= SI_DATA;
+ break;
+ }
+ st = wiz_readb(Sn_SR);
+ if (st >= SOCK_CLOSING && st <= SOCK_UDP)
+ return 0;
+ /* Need IRQ protection to avoid sleep race */
+ if (psleep_flags(&s->s_iflag, flag))
+ return -1;
}
switch (s->s_type) {
case SOCKTYPE_RAW:
/* Now dequeue some bytes into udata.u_base */
wiz_dequeue_u(i, r, udata.u_base);
/* For datagrams we always discard the entire frame */
- wiz_writew_n(Sn_TX_WR0 + i, wiz_readw_n(Sn_TX_WR0 + i)
- + s->s_type == SOCKTYPE_TCP ? r : (n + 8));
+ if (s->s_type == SOCKTYPE_UDP)
+ r = n + 8;
+ wiz_writew(Sn_RX_RD0 + i, wiz_readw(Sn_RX_RD0 + i) + r);
/* FIXME: figure out if SI_DATA should be cleared */
- return r;
+ /* Now tell the device we ate the data */
+ wiz_writeb(Sn_CR, RECV);
}
+ return r;
}
arg_t net_write(struct socket * s, uint8_t flag)
{
uint16_t i = s - sockets;
uint16_t room;
- uint16_t n;
- uint8_t a = s->s_flag & SFLAG_ATMP ? SADDR_TMP : SADDR_SADDR_DST;
+ uint16_t n = 0;;
+ uint8_t a = s->s_flag & SFLAG_ATMP ? SADDR_TMP : SADDR_DST;
+
+ /* FIXME: blocking ?? */
+ used(flag);
i <<= 8;
- room = wiz_readw_n(Sn_TX_FSR + i);
+ room = wiz_readw(Sn_TX_FSR + i);
- switch (s->s_socktype) {
+ switch (s->s_type) {
case SOCKTYPE_UDP:
if (udata.u_count > 1472) {
udata.u_error = EMSGSIZE;
return -1;
}
- case SOCKTYPE_IPRAW:
+ case SOCKTYPE_RAW:
if (udata.u_count > 1500) {
udata.u_error = EMSGSIZE;
return -1;
}
if (room < udata.u_count)
return -2;
- wiz_writel(Sn_DIRPO + i, s->s_addr[a].addr);
+ wiz_writel(Sn_DIPR0 + i, s->s_addr[a].addr);
wiz_writel(Sn_DPORT0 + i, s->s_addr[a].port);
/* Fall through */
case SOCKTYPE_TCP:
return -2;
n = min(room, udata.u_count);
wiz_queue_u(i, n, udata.u_base);
- wiz_writew_n(Sn_TX_WR0 + i,
- wiz_readw_n(Sn_TX_WR0 + i) + n);
+ wiz_writew(Sn_TX_WR0 + i,
+ wiz_readw(Sn_TX_WR0 + i) + n);
+ wiz_writeb(Sn_CR, SEND);
break;
}
- udata.u_count = n;
return n;
}
+arg_t net_shutdown(struct socket *s, uint8_t flag)
+{
+ s->s_iflag |= flag;
+ if (s->s_iflag & SI_SHUTW)
+ wiz_writeb(Sn_CR, DISCON);
+ /* Really we need to look for SHUTR and received data and CLOSE if
+ so - FIXME */
+ return 0;
+}
+
/* Everything below this line is still pure sketching of ideas as we don't
really have a configuration interface designed yet ! */
"eth0", /* Good a name as any */
0, /* No special flags */
};
-
+#if 0
/* Only some of these hit this code, most are handled by the core */
arg_t net_ioctl(uint8_t op, void *p)
{
wiz_bwrite(SHAR0, p, 6);
break;
case OP_GPHY:
- return (wiz_bread(PSTATUS) & 0x20) ? LINK_UP : LINK_DOWN;
+ return (wiz_readb(PSTATUS) & 0x20) ? LINK_UP : LINK_DOWN;
default:
return -EINVAL;
}
return 0;
}
+#endif
+static uint32_t ipa = 0x00000000; /* Tmp hack */
+static uint8_t fakeaddr[6] = { 0xC0, 0xFF, 0xEE, 0xC0, 0xFF, 0xEE };
+static uint32_t iga = 0x020000C0;
+static uint32_t igm = 0x00FFFFFF;
void netdev_init(void)
{
uint16_t i;
- for (i = 0; i < 8; i++) {
- wiz_writeb(Sn_RXMEM_SIZE + (i << 8), 0x2000);
- wiz_writeb(Sn_TXMEM_SIZE + (i << 8), 0x2000);
+ /* We run all the time in indirect, autoinc */
+ mr = MR_AUTOINC|MR_INDIRECT;
+ wiz_writeb(IMR, 0);
+// wiz_writeb(RTR, );
+// wiz_writeb(RCR, );
+ /* Set GAR, SHAR, SUBR, SIPR to defaults ? */
+ wiz_bwrite(SIPR0, &ipa, 4);
+ wiz_bwrite(GAR0, &iga, 4);
+ wiz_bwrite(SUBR0, &igm, 4);
+ wiz_bwrite(SHAR0, fakeaddr, 6);
+ wiz_writeb(RMSR, 0x55); /* 2k a socket */
+ wiz_writeb(TMSR, 0x55); /* 2k a socket */
+ for (i = 0; i < 4 * 256; i += 256) {
+ /* Do we need to set anything here */
}
}
+
+#endif