summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/i386/pc386/network/network.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1998-08-31 23:06:50 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1998-08-31 23:06:50 +0000
commitd9d75fce47b63f287ff553db156c40bda3eceaf1 (patch)
tree91bf8143732c4923edef4d223e86a12e342ad9d1 /c/src/lib/libbsp/i386/pc386/network/network.c
parentPatch from Eric Valette <valette@crf.canon.fr>: (diff)
downloadrtems-d9d75fce47b63f287ff553db156c40bda3eceaf1.tar.bz2
Patch from Emmanuel Raguet <raguet@crf.canon.fr>:
I have reworked the ethernet driver for the BSP pc386 and here is the patch to apply.
Diffstat (limited to '')
-rw-r--r--c/src/lib/libbsp/i386/pc386/network/network.c783
1 files changed, 436 insertions, 347 deletions
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 <bsp.h>
#include <wd80x3.h>
+
+#include <stdio.h>
+#include <stdarg.h>
#include <rtems/error.h>
-#include <ka9q/rtems_ka9q.h>
-#include <ka9q/global.h>
-#include <ka9q/enet.h>
-#include <ka9q/iface.h>
-#include <ka9q/netuser.h>
-#include <ka9q/trace.h>
-#include <ka9q/commands.h>
-#include <ka9q/domain.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
#include <irq.h>
#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; i1<MARsize; i1++) /* clear multicast */
outport_byte(tport+MAR+i1, 0);
@@ -283,287 +259,400 @@ wd8003Enet_initialize_hardware (wd80x3EnetDriver *dp, int broadcastFlag)
/*
* Set up interrupts
*/
- dp->irqInfo.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;
+};