From d9d75fce47b63f287ff553db156c40bda3eceaf1 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Mon, 31 Aug 1998 23:06:50 +0000 Subject: Patch from Emmanuel Raguet : I have reworked the ethernet driver for the BSP pc386 and here is the patch to apply. --- c/src/lib/libbsp/i386/pc386/network/network.c | 783 ++++++++++++++------------ 1 file changed, 436 insertions(+), 347 deletions(-) (limited to 'c/src/lib/libbsp/i386/pc386/network/network.c') diff --git a/c/src/lib/libbsp/i386/pc386/network/network.c b/c/src/lib/libbsp/i386/pc386/network/network.c index 639d2eb699..1f937bc009 100644 --- a/c/src/lib/libbsp/i386/pc386/network/network.c +++ b/c/src/lib/libbsp/i386/pc386/network/network.c @@ -1,92 +1,115 @@ /* - * XXX This driver needs to be reworked to support the new BSD stack - * - * RTEMS/KA9Q driver for WD8003 Ethernet Controller + * RTEMS driver for M68360 WD1 Ethernet * + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca * * $Id$ */ + #include #include + +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + #include #define ET_MINLEN 60 /* minimum message length */ /* - * Number of SCCs supported by this driver + * Number of WDs supported by this driver */ -#define NSCCDRIVER 1 +#define NWDDRIVER 1 /* * Default number of buffer descriptors set aside for this driver. * The number of transmit buffer descriptors has to be quite large * since a single frame often uses four or more buffer descriptors. */ - #define RX_BUF_COUNT 15 #define TX_BUF_COUNT 4 #define TX_BD_PER_BUF 4 /* - * RTEMS event used by interrupt handler to signal daemons. - * This must *not* be the same event used by the KA9Q task synchronization. + * RTEMS event used by interrupt handler to signal driver tasks. + * This must not be any of the events used by the network task synchronization. */ #define INTERRUPT_EVENT RTEMS_EVENT_1 /* - * Receive buffer size -- Allow for a full ethernet packet plus a pointer + * RTEMS event used to start transmit daemon. + * This must not be the same as INTERRUPT_EVENT. + */ +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +/* + * Receive buffer size -- Allow for a full ethernet packet including CRC */ -#define RBUF_SIZE (1520 + sizeof (struct iface *)) +#define RBUF_SIZE 1520 + +#if (MCLBYTES < RBUF_SIZE) +# error "Driver must have MCLBYTES > RBUF_SIZE" +#endif /* - * Hardware-specific storage + * Per-device data */ -typedef struct { +struct wd_softc { + struct arpcom arpcom; rtems_irq_connect_data irqInfo; struct mbuf **rxMbuf; struct mbuf **txMbuf; - unsigned int port; - unsigned char *base; - unsigned long bpar; + int acceptBroadcast; int rxBdCount; int txBdCount; int txBdHead; int txBdTail; int txBdActiveCount; - struct iface *iface; - rtems_id txWaitTid; + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + unsigned int port; + unsigned char *base; + unsigned long bpar; /* * Statistics */ - unsigned long rxInterrupts; - unsigned long rxNotFirst; - unsigned long rxNotLast; - unsigned long rxGiant; - unsigned long rxNonOctet; - unsigned long rxRunt; - unsigned long rxBadCRC; - unsigned long rxOverrun; - unsigned long rxCollision; + unsigned long rxInterrupts; + unsigned long rxNotFirst; + unsigned long rxNotLast; + unsigned long rxGiant; + unsigned long rxNonOctet; + unsigned long rxRunt; + unsigned long rxBadCRC; + unsigned long rxOverrun; + unsigned long rxCollision; - unsigned long txInterrupts; - unsigned long txDeferred; - unsigned long txHeartbeat; - unsigned long txLateCollision; - unsigned long txRetryLimit; - unsigned long txUnderrun; - unsigned long txLostCarrier; - unsigned long txRawWait; -}wd80x3EnetDriver; + unsigned long txInterrupts; + unsigned long txDeferred; + unsigned long txHeartbeat; + unsigned long txLateCollision; + unsigned long txRetryLimit; + unsigned long txUnderrun; + unsigned long txLostCarrier; + unsigned long txRawWait; +}; #define RO 0x10 @@ -96,39 +119,26 @@ typedef struct { #define OUTPAGE ((SHATOT-(MAXSIZ+SHAPAGE-1))/SHAPAGE) static unsigned long loopc; - -static wd80x3EnetDriver wd8003EnetDriver[NSCCDRIVER]; +static volatile unsigned long overrun; +static volatile unsigned long resend; +static struct wd_softc wd_softc[NWDDRIVER]; /* - * WD8003 interrupt handler. The code as it is cleraly showes that - * only one driver is connected. In order to change this a table - * making the correspondance between the current irq number and - * the corresponding wd8003EnetDriver structure could be used... + * WD interrupt handler */ -static void wd8003Enet_interrupt_handler () +static rtems_isr +wd8003Enet_interrupt_handler (rtems_vector_number v) { unsigned int tport, nowTicks, bootTicks; unsigned char status, status2; - struct iface *iface = (struct iface *)(wd8003EnetDriver[0].iface); - wd80x3EnetDriver *dp = (wd80x3EnetDriver *)&wd8003EnetDriver[0]; - struct mbuf *bp; - unsigned int i2; - unsigned int len; - unsigned char start, next, current; - char *shp, *temp; - - tport = wd8003EnetDriver[0].port ; - - /* - * Drop chips interrupt - */ - outport_byte(tport+IMR, 0x00); + tport = wd_softc[0].port ; /* * Read status */ inport_byte(tport+ISR, status); + outport_byte(tport+IMR, 0x00); /* * Ring overwrite @@ -145,56 +155,20 @@ static void wd8003Enet_interrupt_handler () status |= (status2 & (MSK_PTX+MSK_TXE)) ; /* TX status */ outport_byte(tport+TCR, MSK_LOOP); /* loopback mode */ outport_byte(tport+CMDR, MSK_STA + MSK_RD2); /* start */ - } - - /* - * Frame received? - */ - while (status & (MSK_PRX+MSK_RXE)) { - outport_byte(tport+ISR, status & (MSK_PRX+MSK_RXE)); - inport_byte(tport+BNRY, start); - start += 1; - shp = dp->base + 1 + (SHAPAGE * start); - next = *shp++; - len = *((short *)shp)++ - 4; - if (start >= OUTPAGE || next >= OUTPAGE) - break; - bp = ambufw (RBUF_SIZE); - bp->data += sizeof (struct iface *); - temp = bp->data; - bp->cnt = len; - - if ((i2 = (OUTPAGE - start) * SHAPAGE - 4) < len){ - memcpy(temp, shp, i2); - len -= i2; - temp += i2; - shp = dp->base; - } - memcpy(temp, shp, len); - - net_route (iface, &bp); - outport_byte(tport+BNRY, next-1); - outport_byte(tport+CMDR, MSK_PG1 + MSK_RD2); - inport_byte(tport+CURR, current); - outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2); - if (current == next) - break; + overrun = 1 ; + if ((status & (MSK_PTX+MSK_TXE)) == 0) + resend = 1; } /* - * Ring overwrite + * Frame received? */ - if (status & MSK_OVW) { - outport_byte(tport+ISR, MSK_OVW); /* reset IR */ - outport_byte(tport+TCR, 0); /* out of loopback */ - if ((status & (MSK_PTX+MSK_TXE)) == 0) - outport_byte(tport+CMDR, MSK_TXP + MSK_RD2); /* resend */ + if (status & (MSK_PRX+MSK_RXE)) { + outport_byte(tport+ISR, status & (MSK_PRX+MSK_RXE)); + wd_softc[0].rxInterrupts++; + rtems_event_send (wd_softc[0].rxDaemonTid, INTERRUPT_EVENT); } - /* - * Enable chip interrupts - */ - outport_byte(tport+IMR, 0x15); } static void nopOn(const rtems_irq_connect_data* notUsed) @@ -214,32 +188,34 @@ static int wdIsOn(const rtems_irq_connect_data* irq) * Initialize the ethernet hardware */ static void -wd8003Enet_initialize_hardware (wd80x3EnetDriver *dp, int broadcastFlag) +wd8003Enet_initialize_hardware (struct wd_softc *sc) { int i1, ultra; char cc1, cc2; unsigned char temp; - rtems_status_code sc; + rtems_status_code st; unsigned int tport; + unsigned char *hwaddr; - tport = dp->port; + tport = sc->port; /* address from board ROM */ inport_byte(tport+0x04, temp); outport_byte(tport+0x04, temp & 0x7f); + hwaddr = sc->arpcom.ac_enaddr; for (i1=cc2=0; i1<8; i1++) { inport_byte(tport + ADDROM + i1, cc1); cc2 += cc1; if (i1 < 6) - dp->iface->hwaddr[i1] = cc1; + hwaddr[i1] = cc1; } inport_byte(tport+0x04, temp); outport_byte(tport+0x04, temp | 0x80); /* alternate registers */ outport_byte(tport+W83CREG, MSK_RESET); /* reset board, set buffer */ outport_byte(tport+W83CREG, 0); - outport_byte(tport+W83CREG, MSK_ENASH + (int)((dp->bpar>>13)&0x3f)); + outport_byte(tport+W83CREG, MSK_ENASH + (int)((sc->bpar>>13)&0x3f)); outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2); cc1 = MSK_BMS + MSK_FT10; /* configure 8 or 16 bits */ @@ -258,12 +234,12 @@ wd8003Enet_initialize_hardware (wd80x3EnetDriver *dp, int broadcastFlag) outport_byte(tport+PSTART, 0); /* init PSTART */ outport_byte(tport+BNRY, -1); /* init BNRY */ outport_byte(tport+ISR, -1); /* clear IR's */ - outport_byte(tport+IMR, 0x15); /* 0x17 enable interrupt */ + outport_byte(tport+IMR, 0x15); /* enable interrupt */ outport_byte(tport+CMDR, MSK_PG1 + MSK_RD2); for (i1=0; i1<6; i1++) /* initial physical addr */ - outport_byte(tport+PAR+i1, dp->iface->hwaddr[i1]); + outport_byte(tport+PAR+i1, hwaddr[i1]); for (i1=0; i1irqInfo.hdl = wd8003Enet_interrupt_handler; - dp->irqInfo.on = nopOn; - dp->irqInfo.off = nopOn; - dp->irqInfo.isOn = wdIsOn; + sc->irqInfo.hdl = wd8003Enet_interrupt_handler; + sc->irqInfo.on = nopOn; + sc->irqInfo.off = nopOn; + sc->irqInfo.isOn = wdIsOn; - sc = pc386_install_rtems_irq_handler (&dp->irqInfo); - if (!sc) + st = pc386_install_rtems_irq_handler (&sc->irqInfo); + if (!st) rtems_panic ("Can't attach WD interrupt handler for irq %d\n", - dp->irqInfo.name); + sc->irqInfo.name); } - -/* - * Send raw packet (caller provides header). - * This code runs in the context of the interface transmit - * task or in the context of the network task. - */ -static int -wd8003Enet_raw (struct iface *iface, struct mbuf **bpp) +static void +wd_rxDaemon (void *arg) { - wd80x3EnetDriver *dp = &wd8003EnetDriver[iface->dev]; - struct mbuf *bp; - unsigned int len, tport; - char *shp; + unsigned int tport; + struct ether_header *eh; + struct wd_softc *dp = (struct wd_softc *)&wd_softc[0]; + struct ifnet *ifp = &dp->arpcom.ac_if; + struct mbuf *m; + unsigned int i2; + unsigned int len; + volatile unsigned char start, next, current; + char *shp, *temp; + rtems_event_set events; - tport = dp->port; - - /* - * Fill in some logging data - */ - iface->rawsndcnt++; - iface->lastsent = secclock (); - dump (iface, IF_TRACE_OUT, *bpp); - + tport = wd_softc[0].port ; + + for (;;){ + + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + for (;;){ + inport_byte(tport+BNRY, start); + + outport_byte(tport+CMDR, MSK_PG1 + MSK_RD2); + inport_byte(tport+CURR, current); + outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2); + + start += 1; + if (start >= OUTPAGE){ + start = 0; + } + + if (current == start) + break; + + shp = dp->base + 1 + (SHAPAGE * start); + next = *shp++; + len = *((short *)shp)++ - 4; + + if (next >= OUTPAGE){ + next = 0; + } + + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + + temp = m->m_data; + m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); + + if ((i2 = (OUTPAGE - start) * SHAPAGE - 4) < len){ + memcpy(temp, shp, i2); + len -= i2; + temp += i2; + shp = dp->base; + } + memcpy(temp, shp, len); + + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + + outport_byte(tport+BNRY, next-1); + } + /* - * It would not do to have two tasks active in the transmit - * loop at the same time. - * The blocking is simple-minded since the odds of two tasks - * simultaneously attempting to use this code are low. The only - * way that two tasks can try to run here is: - * 1) Task A enters this code and ends up having to - * wait for a transmit buffer descriptor. - * 2) Task B gains control and tries to transmit a packet. - * The RTEMS/KA9Q scheduling semaphore ensures that there - * are no race conditions associated with manipulating the - * txWaitTid variable. + * Ring overwrite */ + if (overrun){ + outport_byte(tport+ISR, MSK_OVW); /* reset IR */ + outport_byte(tport+TCR, 0); /* out of loopback */ + if (resend == 1) + outport_byte(tport+CMDR, MSK_TXP + MSK_RD2); /* resend */ + resend = 0; + overrun = 0; + } + + outport_byte(tport+IMR, 0x15); /* re-enable IT rx */ + } +} + +static void +sendpacket (struct ifnet *ifp, struct mbuf *m) +{ + struct wd_softc *dp = ifp->if_softc; + struct mbuf *n; + unsigned int len, tport; + char *shp; + + tport = dp->port; + - if (dp->txWaitTid) { - dp->txRawWait++; - while (dp->txWaitTid) - rtems_ka9q_ppause (10); - } - - if (dp->txWaitTid == 0) - rtems_task_ident (0, 0, &dp->txWaitTid); - bp = *bpp; len = 0; shp = dp->base + (SHAPAGE * OUTPAGE); - /*rtems_interrupt_disable(level);*/ + n = m; for (;;){ - len += bp->cnt; - memcpy(shp, (char *)bp->data, bp->cnt); - shp += bp->cnt ; - if ((bp = bp->next) == NULL) + len += m->m_len; + memcpy(shp, (char *)m->m_data, m->m_len); + shp += m->m_len ; + if ((m = m->m_next) == NULL) break; } - free_p(bpp); - + m_freem(n); + if (len < ET_MINLEN) len = ET_MINLEN; outport_byte(tport+TBCR0, len); outport_byte(tport+TBCR1, (len >> 8) ); outport_byte(tport+TPSR, OUTPAGE); outport_byte(tport+CMDR, MSK_TXP + MSK_RD2); +} + +/* + * Driver transmit daemon + */ +void +wd_txDaemon (void *arg) +{ + struct wd_softc *sc = (struct wd_softc *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; + + for (;;) { + /* + * Wait for packet + */ + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + + /* + * Send packets till queue is empty + */ + for (;;) { + /* + * Get the next mbuf chain to transmit. + */ + IF_DEQUEUE(&ifp->if_snd, m); + if (!m) + break; + sendpacket (ifp, m); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} + +/* + * Send packet (caller provides header). + */ +static void +wd_start (struct ifnet *ifp) +{ + struct wd_softc *sc = ifp->if_softc; + + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +/* + * Initialize and start the device + */ +static void +wd_init (void *arg) +{ + struct wd_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) { + + /* + * Set up WD hardware + */ + wd8003Enet_initialize_hardware (sc); + + /* + * Start driver tasks + */ + sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, wd_txDaemon, sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, wd_rxDaemon, sc); + } /* - * Show that we've finished with the packet + * Tell the world that we're running. */ - dp->txWaitTid = 0; - return 0; - -} + ifp->if_flags |= IFF_RUNNING; +} /* - * Shut down the interface - * FIXME: This is a pretty simple-minded routine. It doesn't worry - * about cleaning up mbufs, shutting down daemons, etc. + * Stop the device */ -static int -wd8003Enet_stop (struct iface *iface) +static void +wd_stop (struct wd_softc *sc) { unsigned int tport; unsigned char temp; + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + /* * Stop the transmitter */ - tport=wd8003EnetDriver[0].port ; + tport=wd_softc[0].port ; inport_byte(tport+0x04,temp); outport_byte(tport+0x04, temp & 0x7f); outport_byte(tport + CMDR, MSK_STP + MSK_RD2); - return 0; + } + /* * Show interface statistics */ static void -wd8003Enet_show (struct iface *iface) +wd_stats (struct wd_softc *sc) { - printf (" Rx Interrupts:%-8lu", wd8003EnetDriver[0].rxInterrupts); - printf (" Not First:%-8lu", wd8003EnetDriver[0].rxNotFirst); - printf (" Not Last:%-8lu\n", wd8003EnetDriver[0].rxNotLast); - printf (" Giant:%-8lu", wd8003EnetDriver[0].rxGiant); - printf (" Runt:%-8lu", wd8003EnetDriver[0].rxRunt); - printf (" Non-octet:%-8lu\n", wd8003EnetDriver[0].rxNonOctet); - printf (" Bad CRC:%-8lu", wd8003EnetDriver[0].rxBadCRC); - printf (" Overrun:%-8lu", wd8003EnetDriver[0].rxOverrun); - printf (" Collision:%-8lu\n", wd8003EnetDriver[0].rxCollision); - printf (" Tx Interrupts:%-8lu", wd8003EnetDriver[0].txInterrupts); - printf (" Deferred:%-8lu", wd8003EnetDriver[0].txDeferred); - printf (" Missed Hearbeat:%-8lu\n", wd8003EnetDriver[0].txHeartbeat); - printf (" No Carrier:%-8lu", wd8003EnetDriver[0].txLostCarrier); - printf ("Retransmit Limit:%-8lu", wd8003EnetDriver[0].txRetryLimit); - printf (" Late Collision:%-8lu\n", wd8003EnetDriver[0].txLateCollision); - printf (" Underrun:%-8lu", wd8003EnetDriver[0].txUnderrun); - printf (" Raw output wait:%-8lu\n", wd8003EnetDriver[0].txRawWait); + printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); + printf (" Not First:%-8lu", sc->rxNotFirst); + printf (" Not Last:%-8lu\n", sc->rxNotLast); + printf (" Giant:%-8lu", sc->rxGiant); + printf (" Runt:%-8lu", sc->rxRunt); + printf (" Non-octet:%-8lu\n", sc->rxNonOctet); + printf (" Bad CRC:%-8lu", sc->rxBadCRC); + printf (" Overrun:%-8lu", sc->rxOverrun); + printf (" Collision:%-8lu\n", sc->rxCollision); + + printf (" Tx Interrupts:%-8lu", sc->txInterrupts); + printf (" Deferred:%-8lu", sc->txDeferred); + printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat); + printf (" No Carrier:%-8lu", sc->txLostCarrier); + printf ("Retransmit Limit:%-8lu", sc->txRetryLimit); + printf (" Late Collision:%-8lu\n", sc->txLateCollision); + printf (" Underrun:%-8lu", sc->txUnderrun); + printf (" Raw output wait:%-8lu\n", sc->txRawWait); } /* - * Attach an WD8003 driver to the system - * This is the only `extern' function in the driver. - * - * argv[0]: interface label, e.g., "rtems" - * The remainder of the arguemnts are key/value pairs: - * mtu ## -- maximum transmission unit, default 1500 - * broadcast y/n -- accept or ignore broadcast packets, default yes - * rbuf ## -- Set number of receive buffer descriptors - * rbuf ## -- Set number of transmit buffer descriptors - * ip ###.###.###.### -- IP address - * ether ##:##:##:##:##:## -- Ethernet address - * irno -- Set controller irq - * port -- Set io port - * bpar -- Set RAM address + * Driver ioctl handler */ -int -rtems_ka9q_driver_attach (int argc, char *argv[], void *p) +static int +wd_ioctl (struct ifnet *ifp, int command, caddr_t data) { - struct iface *iface; - wd80x3EnetDriver *dp; - char *cp; - int i; - int argIndex; - int broadcastFlag; - char cbuf[30]; - - /* - * Find a free driver - */ - for (i = 0 ; i < NSCCDRIVER ; i++) { - if (wd8003EnetDriver[i].iface == NULL) - break; - } - if (i >= NSCCDRIVER) { - printf ("Too many SCC drivers.\n"); - return -1; - } - if (if_lookup (argv[0]) != NULL) { - printf ("Interface %s already exists\n", argv[0]); - return -1; - } - dp = &wd8003EnetDriver[i]; - - /* - * Create an inteface descriptor - */ - iface = callocw (1, sizeof *iface); - iface->name = strdup (argv[0]); - - /* - * Set default values - */ - broadcastFlag = 1; - dp->txWaitTid = 0; - dp->rxBdCount = RX_BUF_COUNT; - dp->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF; - dp->irqInfo.name = (rtems_irq_symbolic_name) 5; - dp->port = 0x240; - dp->base = (unsigned char*) 0xD0000; - dp->bpar = 0xD0000; - iface->mtu = 1500; - iface->addr = Ip_addr; - iface->hwaddr = mallocw (EADDR_LEN); - memset (iface->hwaddr, 0x08, EADDR_LEN); - - /* - * Parse arguments - */ - for (argIndex = 1 ; argIndex < (argc - 1) ; argIndex++) { - if (strcmp ("mtu", argv[argIndex]) == 0) { - iface->mtu = atoi (argv[++argIndex]); - } - else if (strcmp ("broadcast", argv[argIndex]) == 0) { - if (*argv[++argIndex] == 'n') - broadcastFlag = 0; - } - else if (strcmp ("rbuf", argv[argIndex]) == 0) { - dp->rxBdCount = atoi (argv[++argIndex]); - } - else if (strcmp ("tbuf", argv[argIndex]) == 0) { - dp->txBdCount = atoi (argv[++argIndex]) * TX_BD_PER_BUF; - } - else if (strcmp ("ip", argv[argIndex]) == 0) { - iface->addr = resolve (argv[++argIndex]); - } - else if (strcmp ("ether", argv[argIndex]) == 0) { - argIndex++; - gether (iface->hwaddr, argv[argIndex]); - } - else if (strcmp ("irno", argv[argIndex]) == 0) { - dp->irqInfo.name = (rtems_irq_symbolic_name) atoi (argv[++argIndex]); - } - else if (strcmp ("port", argv[argIndex]) == 0) { - sscanf(argv[++argIndex], "%x", &(dp->port)); - } - else if (strcmp ("bpar", argv[argIndex]) == 0) { - sscanf(argv[++argIndex], "%x", (unsigned *) &(dp->bpar)); - dp->base = (unsigned char *)(dp->bpar); - } - else { - printf ("Argument %d (%s) is invalid.\n", argIndex, argv[argIndex]); - return -1; - } - } - printf ("Ethernet address: %s\n", pether (cbuf, iface->hwaddr)); - printf ("Internet address: %s\n", inet_ntoa(iface->addr)); - printf ("Irno: %X, port: %X, bpar: %X, base: %X\n",dp->irqInfo.name, dp->port, - (unsigned) dp->bpar, (unsigned) dp->base); - fflush(stdout); - /* - * Fill in remainder of interface configuration - */ - iface->dev = i; - iface->raw = wd8003Enet_raw; - iface->stop = wd8003Enet_stop; - iface->show = wd8003Enet_show; - dp->iface = iface; - setencap (iface, "Ethernet"); - - /* - * Set up SCC hardware - */ - wd8003Enet_initialize_hardware (dp, broadcastFlag); - fflush(stdout); - - /* - * Chain onto list of interfaces - */ - iface->next = Ifaces; - Ifaces = iface; - - /* calibrate a delay loop for 2 milliseconds */ - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &loopc ); - loopc /= 500; - - /* - * Start I/O daemons - */ - cp = if_name (iface, " tx"); - iface->txproc = newproc (cp, 1024, if_tx, iface->dev, iface, NULL, 0); - free (cp); - return 0; -} - - - - - - + struct wd_softc *sc = ifp->if_softc; + int error = 0; + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + wd_stop (sc); + break; + + case IFF_UP: + wd_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + wd_stop (sc); + wd_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + wd_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + return error; +} +/* + * Attach an WD driver to the system + */ +int +rtems_wd_driver_attach (struct rtems_bsdnet_ifconfig *config) +{ + struct wd_softc *sc; + struct ifnet *ifp; + int mtu; + int i; + + /* + * Find a free driver + */ + for (i = 0 ; i < NWDDRIVER ; i++) { + sc = &wd_softc[i]; + ifp = &sc->arpcom.ac_if; + if (ifp->if_softc == NULL) + break; + } + if (i >= NWDDRIVER) { + printf ("Too many WD drivers.\n"); + return 0; + } + + /* + * Process options + */ + if (config->hardware_address) { + memcpy (sc->arpcom.ac_enaddr, config->hardware_address, + ETHER_ADDR_LEN); + } + else { + memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN); + } + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + + + if (config->irno) + sc->irqInfo.name = config->irno; + else + sc->irqInfo.name = 5; + + if (config->port) + sc->port = config->port; + else + sc->port = 0x240; + + if (config->bpar) { + sc->bpar = config->bpar; + sc->base = (unsigned char*) config->bpar; + } + else { + sc->bpar = 0xD0000; + sc->base = (unsigned char*) 0xD0000; + } + + sc->acceptBroadcast = !config->ignore_broadcast; + + /* + * Set up network interface values + */ + ifp->if_softc = sc; + ifp->if_unit = i + 1; + ifp->if_name = "wd"; + ifp->if_mtu = mtu; + ifp->if_init = wd_init; + ifp->if_ioctl = wd_ioctl; + ifp->if_start = wd_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + /* calibrate a delay loop for 2 milliseconds */ + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &loopc ); + loopc /= 500; + + /* + * init some variables + */ + overrun = 0; + resend = 0; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + return 1; +}; -- cgit v1.2.3