⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wd8003.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
字号:
/* * RTEMS driver for WD800x * *  Based on the 68360 Network Driver by: *    W. Eric Norum *    Saskatchewan Accelerator Laboratory *    University of Saskatchewan *    Saskatoon, Saskatchewan, CANADA *    eric@skatter.usask.ca * *  $Id: wd8003.c,v 1.4 2002/08/29 15:54:25 ralf Exp $ */#include <bsp.h>#include <wd80x3.h>#include <stdio.h>#include <stdarg.h>#include <string.h>	/* memcpy, memset */#include <rtems/error.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 WDs supported by this driver */#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 driver tasks. * This must not be any of the events used by the network task synchronization. */#define INTERRUPT_EVENT	RTEMS_EVENT_1/* * 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#if (MCLBYTES < RBUF_SIZE)# error "Driver must have MCLBYTES > RBUF_SIZE"#endif/* * Per-device data */struct wd_softc {  struct arpcom			arpcom;  rtems_irq_connect_data	irqInfo;  struct mbuf			**rxMbuf;  struct mbuf			**txMbuf;  int				acceptBroadcast;  int				rxBdCount;  int				txBdCount;  int				txBdHead;  int				txBdTail;  int				txBdActiveCount;  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	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#define SHATOT (8*1024)		/* size of shared memory */#define SHAPAGE 256		/* shared memory information */#define MAXSIZ 	1536		/*(MAXBUF - MESSH_SZ)*/#define OUTPAGE ((SHATOT-(MAXSIZ+SHAPAGE-1))/SHAPAGE)static volatile unsigned long overrun;static volatile unsigned long resend;static struct wd_softc wd_softc[NWDDRIVER];/* * WD interrupt handler */static voidwd8003Enet_interrupt_handler (void){  unsigned int tport;  unsigned char status, status2;  tport = wd_softc[0].port ;  /*   * Read status   */  inport_byte(tport+ISR, status);  outport_byte(tport+IMR, 0x00);  /*   * Ring overwrite   */  if (status & MSK_OVW){    outport_byte(tport+CMDR, MSK_STP + MSK_RD2);	/* stop 8390 */    Wait_X_ms(2);    outport_byte(tport+RBCR0, 0);			/* clear byte count */    outport_byte(tport+RBCR1, 0);    inport_byte(tport+ISR, status2);    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 */    overrun = 1 ;    if ((status & (MSK_PTX+MSK_TXE)) == 0)	resend = 1;  }  /*   * Frame received?   */  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);      }}static void nopOn(const rtems_irq_connect_data* notUsed){  /*   * code should be moved from wd8003Enet_initialize_hardware   * to this location   */}static int wdIsOn(const rtems_irq_connect_data* irq){  return BSP_irq_enabled_at_i8259s (irq->name);}/* * Initialize the ethernet hardware */static voidwd8003Enet_initialize_hardware (struct wd_softc *sc){  int  i1, ultra;  char cc1, cc2;  unsigned char  temp;  rtems_status_code st;  unsigned int tport;  unsigned char *hwaddr;  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)      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)((sc->bpar>>13)&0x3f));  outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2);  cc1 = MSK_BMS + MSK_FT10; /* configure 8 or 16 bits */  inport_byte(tport+0x07, temp) ;   ultra = ((temp & 0xf0) == 0x20 || (temp & 0xf0) == 0x40);  if (ultra)    cc1 = MSK_WTS + MSK_BMS + MSK_FT10;  outport_byte(tport+DCR, cc1);  outport_byte(tport+RBCR0, 0);  outport_byte(tport+RBCR1, 0);  outport_byte(tport+RCR, MSK_MON);	       	/* disable the rxer */  outport_byte(tport+TCR, 0);			/* normal operation */  outport_byte(tport+PSTOP, OUTPAGE);		/* init PSTOP */  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);	       	/* enable interrupt */  outport_byte(tport+CMDR, MSK_PG1 + MSK_RD2);  for (i1=0; i1<6; i1++)			/* initial physical addr */    outport_byte(tport+PAR+i1, hwaddr[i1]);  for (i1=0; i1<MARsize; i1++)			/* clear multicast */    outport_byte(tport+MAR+i1, 0);  outport_byte(tport+CURR, 0);			/* init current packet */  outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2);  outport_byte(tport+CMDR, MSK_STA + MSK_RD2);	/* put 8390 on line */  outport_byte(tport+RCR, MSK_AB);		/* MSK_AB accept broadcast */    if (ultra) {    inport_byte(tport+0x0c, temp);    outport_byte(tport+0x0c, temp | 0x80);    outport_byte(tport+0x05, 0x80);    outport_byte(tport+0x06, 0x01);  }    /*   * Set up interrupts   */  sc->irqInfo.hdl = wd8003Enet_interrupt_handler;  sc->irqInfo.on  = nopOn;  sc->irqInfo.off = nopOn;  sc->irqInfo.isOn = wdIsOn;    st = BSP_install_rtems_irq_handler (&sc->irqInfo);  if (!st)    rtems_panic ("Can't attach WD interrupt handler for irq %d\n",		  sc->irqInfo.name);}static voidwd_rxDaemon (void *arg){  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 = 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);    }      /*   * 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 voidsendpacket (struct ifnet *ifp, struct mbuf *m){	struct wd_softc *dp = ifp->if_softc;	struct mbuf *n;	unsigned int len, tport;	char *shp, txReady;	tport = dp->port;  /*   * Waiting for Transmitter ready   */	  inport_byte(tport+CMDR, txReady);   while(txReady & MSK_TXP)    inport_byte(tport+CMDR, txReady);   len = 0;  shp = dp->base + (SHAPAGE * OUTPAGE);  n = m;    for (;;){    len += m->m_len;    memcpy(shp, (char *)m->m_data, m->m_len);    shp += m->m_len ;    if ((m = m->m_next) == NULL)      break;  }  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 */voidwd_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 voidwd_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 voidwd_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);  }  /*   * Tell the world that we're running.   */  ifp->if_flags |= IFF_RUNNING;}/* * Stop the device */static voidwd_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=wd_softc[0].port ;  inport_byte(tport+0x04,temp);  outport_byte(tport+0x04, temp & 0x7f);  outport_byte(tport + CMDR, MSK_STP + MSK_RD2);}/* * Show interface statistics */static voidwd_stats (struct wd_softc *sc){	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);}/* * Driver ioctl handler */static intwd_ioctl (struct ifnet *ifp, int command, caddr_t data){	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 */intrtems_wd_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach){	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;	/*	 * init some variables	 */	overrun = 0;	resend = 0; 	/*	 * Attach the interface	 */	if_attach (ifp);	ether_ifattach (ifp);	return 1;};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -