#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/netif.h" #include "etherif.h" #include "../ip/ip.h" /* * dm9000 driver for ci20 */ enum { DM_ADDR = 0xB6000000, DM_DATA = 0xB6000002, DM_NCR = 0x0, DM_NCR_RST = (1<<0), DM_NSR = 0x1, DM_NSR_TX1END = (1<<2), DM_NSR_TX2END = (1<<2), DM_NSR_LNK = (1<<6), DM_NSR_SPD = (1<<7), DM_TXCTL = 0x2, DM_TXCTL_REQ = (1<<0), DM_RXCTL = 0x5, DM_RXCTL_DLONG = (1<<5), DM_RXCTL_DCRC = (1<<4), DM_RXCTL_ALL = (1<<3), DM_RXCTL_PREN = (1<<1), DM_RXCTL_RXEN = (1<<0), DM_EPCR = 0xB, DM_EPAR = 0xC, DM_EPDRL = 0xD, DM_EPDRH = 0xE, DM_PAR = 0x10, DM_GPR = 0x1F, DM_GPR_PHY = (1<<0), DM_MRCMDX = 0xF0, DM_MRCMD = 0xF2, DM_MWCMD = 0xF8, DM_TXPLL = 0xFC, DM_TXPLH = 0xFD, DM_ISR = 0xFE, DM_ISR_PT = (1<<1), DM_ISR_PR = (1<<0), DM_IMR = 0xFF, DM_IMR_PAR = (1<<7), DM_IMR_ROOI = (1<<3), DM_IMR_ROI = (1<<2), DM_IMR_PTI = (1<<1), DM_IMR_PRI = (1<<0), }; typedef struct Ctlr Ctlr; struct Ctlr { Lock; int attach; }; static void dmwr8(u8int reg, u8int val) { *IO(u8int, DM_ADDR) = reg; *IO(u8int, DM_DATA) = val; } static u8int dmrd8(u8int reg) { *IO(u8int, DM_ADDR) = reg; return *IO(u8int, DM_DATA); } static u16int dmphyrd16(u8int reg) { dmwr8(DM_EPAR, 0x40 | reg); dmwr8(DM_EPCR, 0xC); microdelay(100); dmwr8(DM_EPCR, 0); return (dmrd8(DM_EPDRH) << 8) | dmrd8(DM_EPDRL); } static void attach(Ether *edev) { USED(edev); } void dm9000transmit(uchar *buf, int len) { int i; /* copy packet to TX SRAM */ *IO(u8int, DM_ADDR) = DM_MWCMD; for(i = 0; i < len; i++){ *IO(u8int, DM_DATA) = buf[i]; } /* write packet length */ dmwr8(DM_TXPLL, len & 0xFF); dmwr8(DM_TXPLH, (len >> 8) & 0xFF); /* start transmission */ dmwr8(DM_TXCTL, DM_TXCTL_REQ); /* wait for completion */ for(i = 0; i < 100; i++){ if(dmrd8(DM_NSR) & (DM_NSR_TX1END | DM_NSR_TX2END)) break; if(dmrd8(DM_ISR) & DM_ISR_PT) break; delay(10); } if(i == 100){ print("dm9000: transmit timeout\n"); } /* clear interrupt bit */ dmwr8(DM_ISR, DM_ISR_PT); } static void transmit(Ether *edev) { int len; Ctlr *ctlr; Block *bp; ctlr = edev->ctlr; bp = qget(edev->oq); if(bp == nil) return; len = BLEN(bp); ilock(ctlr); dm9000transmit(bp->rp, len); iunlock(ctlr); freeb(bp); } static int resetme = 0; static void dm9000receive(void) { uchar *p; u8int rdy, ll, lh; u16int i, status, length; Etherpkt pkt; Ip4hdr *ip4hdr; rdy = dmrd8(DM_ISR); print("ISR=%8.8hhub\n", rdy); if(!(rdy & DM_ISR_PR)){ print("no packet today\n"); return; } print("there is a packet !!!\n"); dmwr8(DM_ISR, DM_ISR_PR); microdelay(10); for(;;){ /* shrug */ dmrd8(DM_MRCMDX); microdelay(10); rdy = (*IO(u8int, DM_DATA)) & 0x3; print("rdy=%hhub\n", rdy); if(rdy > 1){ print("i need a reset\n"); dmwr8(DM_IMR, DM_IMR_PAR); dmwr8(DM_ISR, 0xF); dmwr8(DM_RXCTL, 0); resetme = 1; return; } print("NCR=%8.8hhub NSR=%8.8hhub\n", dmrd8(DM_NCR), dmrd8(DM_NSR)); print("IMR=%8.8hhub\n", dmrd8(DM_IMR)); if(rdy != 1) return; *IO(u8int, DM_ADDR) = DM_MRCMD; rdy = *IO(u8int, DM_DATA); status = *IO(u8int, DM_DATA); ll = *IO(u8int, DM_DATA); lh = *IO(u8int, DM_DATA); print("ll %hhud lh %hhud\n", ll, lh); length = ll + (lh << 8); print("rdy %8.8hhub, status %8.8hub length %hud\n", rdy, status, length); p = pkt.d; for(i = 0; i < length; i++){ p[i] = *IO(u8int, DM_DATA); } ip4hdr = (Ip4hdr*) pkt.data; print("pkt src %E dst %E typ %hhux %hhud\n", pkt.s, pkt.d, pkt.type[0], pkt.type[1]); print("pkt src %V dst %V\n", ip4hdr->src, ip4hdr->dst); } } int dm9000reset(void) { dmwr8(DM_GPR, 0); dmwr8(DM_NCR, DM_NCR_RST); microdelay(100); if(dmrd8(DM_NCR) & 1){ print("dm9000 did not respond to reset"); return -1; } if((dmrd8(DM_ISR) >> 6) != 2) panic("dm9000: unhandled i/o mode"); dmwr8(DM_NCR, 0); dmwr8(DM_TXCTL, 0); dmwr8(DM_RXCTL, DM_RXCTL_DLONG | DM_RXCTL_DCRC | DM_RXCTL_RXEN); dmwr8(DM_IMR, DM_IMR_PAR | DM_IMR_ROOI | DM_IMR_ROI | DM_IMR_PTI | DM_IMR_PRI); int i = 0; while(!(dmphyrd16(1) & 0x20)){ delay(1); i++; if(i == 10000){ print("dm9000: no link\n"); return 0; } } return 0; } static int reset(Ether *edev) { int i; u8int r; if(dm9000reset() < 0) return -1; r = dmrd8(DM_NSR); if(r & DM_NSR_LNK) edev->link = 1; if(r & DM_NSR_SPD) edev->mbps = 100; for(i = 0; i < 6; i++){ edev->ea[i] = dmrd8(DM_PAR+i); } return 0; } static int pnp(Ether *edev) { static Ctlr ct; if(edev->ctlrno != 0) return -1; edev->ctlr = &ct; edev->arg = edev; edev->mbps = 10; edev->port = DM_ADDR; edev->irq = -1; if(reset(edev) < 0){ edev->ctlr = nil; return -1; } return 0; } void etherdm9000clink(void) { addethercard("dm9000", pnp); } void dm9000test(void) { int n; uchar *p; extern ushort ipcsum(uchar*); u16int cs; int srcport = 6665; int dstport = 6666; uchar buf[1500]; uchar dstmac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; uchar srcip[] = { 0xff, 0xff, 0xff, 0xff }; uchar dstip[] = { 0xff, 0xff, 0xff, 0xff }; uchar header[42] = { /* 0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 6 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 12 */ 0x08, 0x00, /* 14 */ 0x45, 0x00, /* 16 */ 0x00, 0x00, /* total length */ /* 18 */ 0x00, 0x00, 0x00, 0x00, /* 22 */ 64, /* ttl */ /* 23 */ 0x11, /* protocol */ /* 24 */ 0x00, 0x00, /* checksum */ /* 26 */ srcip[0], srcip[1], srcip[2], srcip[3], /* 30 */ dstip[0], dstip[1], dstip[2], dstip[3], /* 34 */ srcport >> 8, srcport, dstport >> 8, dstport, /* 38 */ 0x00, 0x00, /* length */ /* 40 */ 0x00, 0x00 /* checksum */ }; dm9000reset(); while(1){ memset(buf, 0, sizeof(buf)); memmove(buf, header, 42); n = 61; p = buf; p[n] = ' '; memset(p+42, 0x42, 10); p[16] = n - 14 >> 8; p[17] = n - 14; p[24] = 0; p[25] = 0; cs = ipcsum((uchar*) p + 14); p[24] = cs >> 8; p[25] = cs; p[38] = n - 34 >> 8; p[39] = n - 34; //memmove(p+Eaddrlen, dstmac, Eaddrlen); dm9000transmit(buf, n); //dm9000receive(); delay(1000); if(resetme > 0){ resetme = 0;dm9000reset(); } delay(50); } }