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

📄 ne2000.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
	next = data;	inport_byte (dport, data);	len = data;	inport_byte (dport, data);	len |= data << 8;      }      else {                        /* Word transfers  */	inport_word (dport, statnext);	inport_word (dport, len);	next = statnext >> 8;      }      outport_byte (port + ISR, MSK_RDC);      if (next >= NE_STOP_PAGE)	next = NE_FIRST_RX_PAGE;      /* The first four bytes of the length are the buffer header.  */      len -= 4;      startaddr = startpage * NE_PAGE_SIZE + 4;      MGETHDR (m, M_WAIT, MT_DATA);      MCLGET (m, M_WAIT);      m->m_pkthdr.rcvif = ifp;      p = mtod (m, unsigned char *);      m->m_len = m->m_pkthdr.len = len - sizeof (struct ether_header);      toend = NE_STOP_PAGE * NE_PAGE_SIZE - startaddr;      if (toend < len) {	ne_read_data (sc, startaddr, toend, p);	p += toend;	len -= toend;	startaddr = NE_FIRST_RX_PAGE * NE_PAGE_SIZE;      }      if (len > 0)	ne_read_data (sc, startaddr, len, p);      eh = mtod (m, struct ether_header *);      m->m_data += sizeof (struct ether_header);      ether_input (ifp, eh, m);      ++sc->stats.rx_packets;      outport_byte (port + BNRY, next - 1);    }    if (sc->overrun) {      outport_byte (port + ISR, MSK_OVW);      outport_byte (port + TCR, 0);      if (sc->resend)	outport_byte (port + CMDR, MSK_PG0 | MSK_TXP | MSK_RD2 | MSK_STA);      sc->resend = 0;      sc->overrun = 0;    }    /* Reenable device interrupts.  */    outport_byte (port + IMR, NE_INTERRUPTS);  }}/* Load an NE2000 packet onto the device.  */static voidne_loadpacket (struct ne_softc *sc, struct mbuf *m){  unsigned int port = sc->port;  unsigned int dport = port + DATAPORT;  struct mbuf *mhold = m;  int leftover;  unsigned char leftover_data;  int timeout;#ifdef DEBUG_NE2000  printk ("Uploading NE2000 packet\n");#endif  /* Reset remote DMA complete flag.  */  outport_byte (port + ISR, MSK_RDC);  /* Write out the count.  */  outport_byte (port + RBCR0, m->m_pkthdr.len);  outport_byte (port + RBCR1, m->m_pkthdr.len >> 8);  sc->sendlen[sc->nextavail] = m->m_pkthdr.len;  /* Tell the device which address we want to write to.  */  outport_byte (port + RSAR0, 0);  outport_byte (port + RSAR1,		NE_FIRST_TX_PAGE + (sc->nextavail * NE_TX_PAGES));  /* Set up the write.  */  outport_byte (port + CMDR, MSK_PG0 | MSK_RWR | MSK_STA);  /* Transfer the mbuf chain to device memory.  NE2000 devices require     that the data be transferred as words, so we need to handle odd     length mbufs.  Never occurs if we force byte transfers. */  leftover = 0;  leftover_data = '\0';  for (; m != NULL; m = m->m_next) {    int len;    unsigned char *data;    len = m->m_len;    if (len == 0)      continue;    data = mtod (m, unsigned char *);    if (leftover) {      unsigned char next;      /* Data left over from previous mbuf in chain.  */      next = *data++;      --len;      outport_word (dport, leftover_data | (next << 8));      leftover = 0;    }    /* If using byte transfers, len always ends up as zero so        there are no leftovers. */    if (sc->byte_transfers)      while (len > 0) {	outport_byte (dport, *data++);	len--;      }    else      while (len > 1) {	outport_word (dport, data[0] | (data[1] << 8));	data += 2;	len -= 2;      }    if (len > 0)      {	leftover = 1;	leftover_data = *data++;      }  }  if (leftover)    outport_word (dport, leftover_data);  m_freem (mhold);  /* Wait for the device to complete accepting the data, with a     limiting counter so that we don't wait too long.  */  for (timeout = 0; timeout < 100; ++timeout)    {      unsigned char status;      inport_byte (port + ISR, status);#ifdef DEBUG_NE2000      if ((status &~ MSK_RDC) != 0)	printk ("Status 0x%x while waiting for acknowledgement of uploaded packet\n",		status);#endif      if ((status & MSK_RDC) != 0) {	outport_byte (port + ISR, MSK_RDC);	break;      }    }  if (timeout >= 100)    printk ("Timed out waiting for acknowledgement of uploaded NE2000 packet\n");  ++sc->nextavail;  if (sc->nextavail == NE_TX_BUFS)    sc->nextavail = 0;}/* Tell the NE2000 to transmit a buffer whose contents we have already   loaded onto the device.  */static voidne_transmit (struct ne_softc *sc){  unsigned int port = sc->port;  int len;#ifdef DEBUG_NE2000  printk ("Transmitting NE2000 packet\n");#endif  len = sc->sendlen[sc->nextsend];  if (len < ET_MINLEN)    len = ET_MINLEN;  outport_byte (port + TBCR0, len);  outport_byte (port + TBCR1, len >> 8);  outport_byte (port + TPSR, NE_FIRST_TX_PAGE + (sc->nextsend * NE_TX_PAGES));  outport_byte (port + CMDR, MSK_PG0 | MSK_TXP | MSK_RD2 | MSK_STA);  ++sc->nextsend;  if (sc->nextsend == NE_TX_BUFS)    sc->nextsend = 0;  ++sc->stats.tx_packets;}/* The NE2000 packet transmit daemon.  This task is started when the   NE2000 driver is initialized.  */static voidne_tx_daemon (void *arg){  struct ne_softc *sc = (struct ne_softc *) arg;  unsigned int port = sc->port;  struct ifnet *ifp = &sc->arpcom.ac_if;  while (1) {    rtems_event_set events;    /* Wait for a packet to be ready for sending, or for there to be       room for another packet in the device memory.  */    rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,				RTEMS_EVENT_ANY | RTEMS_WAIT,				RTEMS_NO_TIMEOUT,				&events);#ifdef DEBUG_NE2000    printk ("ne_tx_daemon\n");#endif    /* This daemon handles both uploading data onto the device and       telling the device to transmit data which has been uploaded.       These are separate tasks, because while the device is       transmitting one buffer we will upload another.  */    /* Don't let the device interrupt us now.  */    outport_byte (port + IMR, 0);    while (1) {      struct mbuf *m;      /* If the device is not transmitting a packet, and we have         uploaded a packet, tell the device to transmit it.  */      if (! sc->transmitting && sc->inuse > 0) {	sc->transmitting = 1;	ne_transmit (sc);      }      /* If we don't have any more buffers to send, quit now.  */      if (ifp->if_snd.ifq_head == NULL) {	ifp->if_flags &= ~IFF_OACTIVE;	break;      }      /* Allocate a buffer to load data into.  If there are none         available, quit until a buffer has been transmitted.  */      if (sc->inuse >= NE_TX_BUFS)	break;      ++sc->inuse;      IF_DEQUEUE (&ifp->if_snd, m);      if (m == NULL)	panic ("ne_tx_daemon");      ne_loadpacket (sc, m);      /* Check the device status.  It may have finished transmitting         the last packet.  */      ne_check_status (sc);    }    /* Reenable device interrupts.  */    outport_byte (port + IMR, NE_INTERRUPTS);  }}/* Start sending an NE2000 packet.  */static voidne_start (struct ifnet *ifp){  struct ne_softc *sc = ifp->if_softc;  /* Tell the transmit daemon to wake up and send a packet.  */  rtems_event_send (sc->tx_daemon_tid, START_TRANSMIT_EVENT);  ifp->if_flags |= IFF_OACTIVE;}/* Initialize and start and NE2000.  */static voidne_init (void *arg){  struct ne_softc *sc = (struct ne_softc *) arg;  struct ifnet *ifp = &sc->arpcom.ac_if;  if (sc->tx_daemon_tid == 0) {    sc->inuse = 0;    sc->nextavail = 0;    sc->nextsend = 0;    sc->transmitting = 0;    ne_init_hardware (sc);    sc->tx_daemon_tid = rtems_bsdnet_newproc ("SCtx", 4096, ne_tx_daemon, sc);    sc->rx_daemon_tid = rtems_bsdnet_newproc ("SCrx", 4096, ne_rx_daemon, sc);  }  ifp->if_flags |= IFF_RUNNING;}/* Stop an NE2000.  */static voidne_stop (struct ne_softc *sc){  unsigned int port = sc->port;  int i;  sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING;  /* Stop everything.  */  outport_byte (port + CMDR, MSK_STP | MSK_RD2);  /* Wait for the interface to stop, using I as a time limit.  */  for (i = 0; i < 5000; ++i)    {      unsigned char status;      inport_byte (port + ISR, status);      if ((status & MSK_RST) != 0)	break;    }  sc->inuse = 0;  sc->nextavail = 0;  sc->nextsend = 0;  sc->transmitting = 0;}/* Show NE2000 interface statistics.  */static voidne_stats (struct ne_softc *sc){  printf ("    Received packets: %-8lu", sc->stats.rx_packets);  printf (" Transmitted packets: %-8lu\n", sc->stats.tx_packets);  printf ("        Receive acks: %-8lu", sc->stats.rx_acks);  printf ("       Transmit acks: %-8lu\n", sc->stats.tx_acks);  printf ("     Packet overruns: %-8lu", sc->stats.overruns);  printf ("        Frame errors: %-8lu\n", sc->stats.rx_frame_errors);  printf ("          CRC errors: %-8lu", sc->stats.rx_crc_errors);  printf ("      Missed packets: %-8lu\n", sc->stats.rx_missed_errors);  printf ("          Interrupts: %-8lu\n", sc->stats.interrupts);}/* NE2000 driver ioctl handler.  */static intne_ioctl (struct ifnet *ifp, int command, caddr_t data){  struct ne_softc *sc = ifp->if_softc;  int error = 0;  switch (command) {  case SIOCGIFADDR:  case SIOCSIFADDR:    error = ether_ioctl (ifp, command, data);    break;  case SIOCSIFFLAGS:    switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {    case IFF_RUNNING:      ne_stop (sc);      break;    case IFF_UP:      ne_init (sc);      break;    case IFF_UP | IFF_RUNNING:      ne_stop (sc);      ne_init (sc);      break;    default:      break;    }    break;  case SIO_RTEMS_SHOW_STATS:    ne_stats (sc);    break;    /* FIXME: Multicast commands must be added here.  */  default:    error = EINVAL;    break;  }  return error;}/* Attach an NE2000 driver to the system.  */intrtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config){  int i;  struct ne_softc *sc;  struct ifnet *ifp;  int mtu;  /* Find a free driver.  */  sc = NULL;  for (i = 0; i < NNEDRIVER; ++i) {    sc = &ne_softc[i];    ifp = &sc->arpcom.ac_if;    if (ifp->if_softc == NULL)      break;  }  if (sc == NULL) {    printf ("Too many NE2000 drivers.\n");    return 0;  }  memset (sc, 0, sizeof *sc);  /* Check whether we do byte-wide or word-wide transfers.  */  #ifdef NE2000_BYTE_TRANSFERS  sc->byte_transfers = TRUE;#else  sc->byte_transfers = FALSE;#endif  /* Handle the options passed in by the caller.  */  if (config->mtu != 0)    mtu = config->mtu;  else    mtu = ETHERMTU;  if (config->irno != 0)    sc->irno = config->irno;  else {    /* We use 5 as the default IRQ.  */    sc->irno = 5;  }  if (config->port != 0)    sc->port = config->port;  else {    /* We use 0x300 as the default IO port number.  */    sc->port = 0x300;  }  sc->accept_broadcasts = ! config->ignore_broadcast;  if (config->hardware_address != NULL)    memcpy (sc->arpcom.ac_enaddr, config->hardware_address,	    ETHER_ADDR_LEN);  else    {      unsigned char prom[16];      int ia;      /* Read the PROM to get the Ethernet hardware address.  */      outport_byte (sc->port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP);      if (sc->byte_transfers) {	outport_byte (sc->port + DCR, MSK_FT10 | MSK_BMS);      }      else {	outport_byte (sc->port + DCR, MSK_FT10 | MSK_BMS | MSK_WTS);      }      outport_byte (sc->port + RBCR0, 0);      outport_byte (sc->port + RBCR1, 0);      outport_byte (sc->port + RCR, MSK_MON);      outport_byte (sc->port + TCR, MSK_LOOP);      outport_byte (sc->port + IMR, 0);      outport_byte (sc->port + ISR, 0xff);      ne_read_data (sc, 0, sizeof prom, prom);      outport_byte (sc->port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP);      for (ia = 0; ia < ETHER_ADDR_LEN; ++ia)	sc->arpcom.ac_enaddr[ia] = prom[ia * 2];    }  /* Set up the network interface.  */  ifp->if_softc = sc;  ifp->if_unit = i + 1;  ifp->if_name = "ne";  ifp->if_mtu = mtu;  ifp->if_init = ne_init;  ifp->if_ioctl = ne_ioctl;  ifp->if_start = ne_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;  /* Attach the interface.  */  if_attach (ifp);  ether_ifattach (ifp);  return 1;}

⌨️ 快捷键说明

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