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

📄 cs8900if.c

📁 LwIP adaptation for Fujitsu MB90f497 and CS8900A Ethernet driver
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2001 Leon Woestenberg <leon.woestenberg@axon.nl> * Copyright (c) 2001 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of Axon Digital Design nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AXON DIGITAL DESIGN AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is a contribution to the lwIP TCP/IP stack. * The Swedish Institute of Computer Science and Adam Dunkels * are specifically granted permission to redistribute this * source code. * * This is a device driver for the Cirrus/Crystal Semiconductor CS8900A * chip in combination with the lwIP stack, release 0.5.0 and higher. * * This is work under development. Please coordinate changes * and requests with Leon Woestenberg <leon.woestenberg@axon.nl> * * The Swedish Institute of Computer Science and Adam Dunkels * are specifically granted permission to redistribute this * source code under any conditions they seem fit. * * A quick function roadmap: * * cs8900_*() are low level, cs8900 hardware specific functions. * These are static functions of the device driver source and * SHOULD NOT need to be called from outside this source. * * cs8900if_*() are the lwIP network interface functions. * * cs8900_interrupt() is an early interrupt service routine (ISR). * It merely sets a flag to indicate the cs8900 needs servicing. * (This function MAY be tied to an interrupt vector, IF present). * * cs8900_service() is the actual interrupt event service routine. * It must be called whenever the cs8900 needs servicing. It MAY * be polled safely (so, you do NOT NEED interrupt support.) * * cs8900_init() sets up the cs8900, using its register set. When * using the driver on your particular hardware platform, make sure * the register setups match. * Function is called from cs8900if_init(). * * cs8900_input() transfers a received packet from the chip. * Function is called from cs8900if_input(). * * cs8900_output() transfers a packet to the chip for transmission. * Function is called from cs8900if_output(). * * cs8900if_init() initializes the lwIP network interface, and * calls cs8900_init() to intialize the hardware. * Function is called from lwIP. * * cs8900if_service() is the service routine, which must be called * upon the need for service, or on a regular basis, in order to * service the Ethernet chip. * * cs8900if_input() calls cs8900_input() to get a received packet * and then forwards the packet to protocol(s) handler(s). * Function is called from cs8900_service(). * * cs8900if_output() resolves the hardware address, then * calls cs8900_output() to transfer the packet. * Function is called from lwIP. * * Future development: * * Split the generic Ethernet functionality (a lot of the * cs8900if_*() functions) and the actual cs8900a dependencies. * * Enhance the interrupt handler to service the Ethernet * chip (to decrease latency); support early packet * inspection (during reception) to early drop unwanted * packets, minimize chip buffer use and maximize throughput. * * Statistics gathering. * */#include "lwip/debug.h"#include "lwip/opt.h"#include "lwip/def.h"#include "lwip/mem.h"#include "lwip/pbuf.h"#include "lwip/stats.h"#include "lwip/sys.h"#include "lwip/arp.h"#include "lwip/lcd.h"#include "lwip/cs8900if.h"#if defined(CS8900_TX_QUEUE) && (CS8900_TX_QUEUE > 0)#  include "lwip/ip.h"#  include "lwip/ip_addr.h"#endif/* Define those to better describe your network interface. */#define IFNAME0 'e'#define IFNAME1 'n'#pragma section FAR_CODE=RAMCODE	/* located the program into RAM */#pragma section CODE=RAMCODEstatic const struct eth_addr ethbroadcast = {{0xffU,0xffU,0xffU,0xffU,0xffU,0xffU}};/* Forward declarations. */static void  cs8900if_input(struct netif *netif);static err_t cs8900if_output(struct netif *netif, struct pbuf *p,			       struct ip_addr *ipaddr);static err_t cs8900_output(struct netif *netif, struct pbuf *p);static struct pbuf *cs8900_input(struct netif *netif);static void cs8900_service(struct netif *netif);/* Define these to match your hardware setup */#define MEM_BASE 0x200000#define IO_BASE 0x0300#define INT_NR 0x00#define IOADR volatile __far unsigned int#define TXCMD    *(IOADR *)(MEM_BASE + IO_BASE + 0x04)#define TXLENGTH *(IOADR *)(MEM_BASE + IO_BASE + 0x06)#define ISQ      *(IOADR *)(MEM_BASE + IO_BASE + 0x08)#define PACKETPP *(IOADR *)(MEM_BASE + IO_BASE + 0x0A)#define PPDATA   *(IOADR *)(MEM_BASE + IO_BASE + 0x0C)#define RXTXREG  *(IOADR *)(MEM_BASE + IO_BASE)// CS8900 PacketPage register offsets#define  CS_PP_EISA        0x0000          // EISA Registration number of CS8900#define  CS_PP_PRODID      0x0002          // Product ID Number#define  CS_PP_IOBASE      0x0020          // I/O Base Address#define  CS_PP_INTNUM      0x0022          // Interrupt number (0,1,2, or 3)#define  CS_PP_RXCFG       0x0102          // Receiver Configuration#define  CS_PP_RXCTL       0x0104          // Receiver Control#define  CS_PP_TXCFG       0x0106          // Transmit Configuration#define  CS_PP_BUFCFG      0x010A          // Buffer Configuration#define  CS_PP_LINECTL     0x0112          // Line Control Register offset#define  CS_PP_SELFCTL     0x0114          // Self Control#define  CS_PP_BUSCTL      0x0116          // Bus Control#define  CS_PP_TESTCTL     0x0118          // Test Control#define  CS_PP_ISQ         0x0120          // Interrupt status queue#define  CS_PP_RXEVENT     0x0124          // Receiver Event#define  CS_PP_TX_EVENT    0x0128          // Transmitter Event#define  CS_PP_BUF_EVENT   0x012C          // Buffer Event#define  CS_PP_RXMISS      0x0130          // Receiver Miss Counter#define  CS_PP_TXCOL       0x0132          // Transmit Collision Counter#define  CS_PP_LINESTATUS  0x0134          // Line Status#define  CS_PP_SELFTEST    0x0136          // Self Status#define  CS_PP_BUSSTATUS   0x0138          // Bus Status#define  CS_PP_TXCMD       0x0144          // Transmit Command Request#define  CS_PP_TXLEN       0x0146          // Transmit Length#define  CS_PP_IA1         0x0158          // Individual Address (IA)#define  CS_PP_IA2         0x015A          // Individual Address (IA)#define  CS_PP_IA3         0x015C          // Individual Address (IA)#define  CS_PP_RXSTATUS    0x0400          // Receive Status#define  CS_PP_RXLEN       0x0402          // Receive Length#define  CS_PP_RXFRAME     0x0404          // Receive Frame Location#define  CS_PP_TXFRAME     0x0A00          // Transmit Frame Location#define ETHADDR0 (0x00U)#define ETHADDR1 (0x03U)#define ETHADDR2 (0x41U)#define ETHADDR3 (0xbbU)#define ETHADDR4 (0xaaU)#define ETHADDR5 (0xddU)static struct netif *cs8900if_netif;// hardware interrupt vector handlervoid cs8900_interrupt(void){  struct cs8900if *cs8900if = cs8900if_netif->state;  if (cs8900if)  {    cs8900if->needs_service = 1;#if (CS8900_STATS > 0)    cs8900if->interrupts++;#endif  }}// cs8900_init()//// initializes the CS8900Astatic voidcs8900_init(struct netif *netif){  u16_t dummy;  /* Obtain MAC address from network interface. */  /* XXX: make up an address. */  ((struct cs8900if *)netif->state)->ethaddr->addr[0] = ETHADDR0;  ((struct cs8900if *)netif->state)->ethaddr->addr[1] = ETHADDR1;  ((struct cs8900if *)netif->state)->ethaddr->addr[2] = ETHADDR2;  ((struct cs8900if *)netif->state)->ethaddr->addr[3] = ETHADDR3;  ((struct cs8900if *)netif->state)->ethaddr->addr[4] = ETHADDR4;  ((struct cs8900if *)netif->state)->ethaddr->addr[5] = ETHADDR5;  // set RESET bit  PACKETPP = CS_PP_SELFCTL;//  PPDATA = 0x0055U;  // { the RESET bit will be cleared by the cs8900a  //   as a result of the reset }  // RESET bit cleared?  while((PPDATA & 0x0040U) != 0); // TODO: add timeout  // { after full initialization of the cs8900a  //   the INITD bit will be set }  PACKETPP = CS_PP_SELFTEST;  // INITD bit still clear?  while ((PPDATA & 0x0080U) == 0); // TODO: add timeout  // { INITD bit is set }  // TODO: check if this is correct and/or necessary  dummy = *(u8_t *)(MEM_BASE + IO_BASE + 0x0D) ;  /* Dummy read, put chip in 16bit-mode */  dummy = *(u16_t *)(MEM_BASE + IO_BASE + 0x0D) ;  // Set MAC address  PACKETPP = CS_PP_IA1;  PPDATA = (u16_t)ETHADDR0 | ((u16_t)ETHADDR1 << 8U);  PACKETPP = CS_PP_IA2;  PPDATA = (u16_t)ETHADDR2 | ((u16_t)ETHADDR3 << 8U);  PACKETPP = CS_PP_IA3;  PPDATA = (u16_t)ETHADDR4 | ((u16_t)ETHADDR5 << 8U);  // accept valid unicast or broadcast frames  PACKETPP = CS_PP_RXCTL;  PPDATA = (0x0005U | 0x0800U/*broadcast*/ | 0x0400U/*individual*/ | 0x0100U/*RxOK*/);  // enable receive interrupt  PACKETPP = CS_PP_RXCFG;  PPDATA = (0x0003U | 0x0100U/*RXIRQ*/);  // disable transmit interrupt (is default)  PACKETPP = CS_PP_TXCFG;  PPDATA = (0x0007U | 0);  // use interrupt number 0  PACKETPP = CS_PP_INTNUM;  PPDATA = (0x0000U);  // generate interrupt event on:  // - the rxMISS counter reaches 0x200, or  // - a received frame is lost  PACKETPP = CS_PP_BUFCFG;  PPDATA = (0x000bU |#if (CS8900_STATS > 0) // interrupt before counter overflow  (0x2000U/*MissOvfloiE*/ | 0x1000U/*TxColOvfloiE*/) |#endif#if (CS8900_STATS > 1) // interrupt on counter increment  (0x0400U/*RxMissiE*/) |#endif  0x0000);  // enable interrupt generation  PACKETPP = CS_PP_BUSCTL;  PPDATA = (0x0017U | 0x8000U/*EnableIRQ*/);  // enable:  // - receiver  // - transmitter  PACKETPP = CS_PP_LINECTL;  PPDATA = (0x0013U | 0x0080U/*SerTxOn*/ | 0x0040U/*SerRxOn*/);}static err_t cs8900_output(struct netif *netif, struct pbuf *p){	int tries = 0;    struct pbuf *q;//Put_String("cs8900_output: call\n");  // exit if link has failed  PACKETPP = CS_PP_LINESTATUS;  if ((PPDATA & 0x0080U/*LinkOK*/) == 0) return ERR_CONN; // no Ethernet link  /* transmit command */  TXCMD = 0x00C9U;  TXLENGTH = p->tot_len;  PACKETPP = CS_PP_BUSSTATUS;  // not ready for transmission and still within 100 retries?  while(((PPDATA & 0x0100U/*Rdy4TxNOW*/) == 0) && (tries++ < 100))  {    // throw away the last committed received frame    PACKETPP = CS_PP_RXCFG;    PPDATA = (0x0003U | 0x0040U/*Skip_1*/ | 0x0100U/*RxOKiE*/);    PACKETPP = CS_PP_BUSSTATUS;    /* cs8900if->dropped++; CHECK: we do not know if we actually will drop a frame here */  }  // ready to transmit?  if((PPDATA & 0x0100U/*Rdy4TxNOW*/) != 0)  {    for(q = p; q != NULL; q = q->next)    {      u16_t i;      u16_t *ptr = (u16_t *)q->payload;      /* Send the data from the pbuf to the interface, one pbuf at a         time. The size of the data in each pbuf is kept in the ->len         variable. */      for(i = 0; i < q->len; i += 2)      {        RXTXREG = *ptr++;      }#if (CS8900_STATS > 0)      ((struct cs8900if *)netif->state)->sentbytes += q->len;#endif    }#if (CS8900_STATS > 0)    ((struct cs8900if *)netif->state)->sentpackets++;#endif  }  return ERR_OK;}/* * cs8900_input(): * * Allocates a pbuf and transfers the bytes of the incoming * packet from the interface into the pbuf. * */// To be called just after reading an ISQ event// containing the "Receiver Event" register.//// This function copies a frame from the CS8900A.// It is designed fail-safe:// - It does not assume a frame is actually present.// - It checks for non-zero length// - It does not overflow the frame bufferstatic struct pbuf *cs8900_input(struct netif *netif){  struct pbuf *p = 0, *q;  u16_t len = 0;  u16_t event_type;  u16_t i;  u16_t *ptr;  // read RxStatus  event_type = RXTXREG;  // correctly received frame, either broadcast or individual address?  // TODO: think where these checks should appear: here or in cs8900_input()  if ((event_type & 0x0100U/*RxOK*/) && (event_type & 0x0c00U/*Broadcast | Individual*/))  {    event_type = 0;    // read RxLength    len = RXTXREG;    DEBUGF(ETH_DEBUG, ("cs8900_input: packet len %u\n", len));    // positive length?    if (len > 0)    {       // allocate a pbuf chain with total length 'len'      p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);      if (p != 0)      {        for (q = p; q != 0; q = q->next)	      {          DEBUGF(ETH_DEBUG, ("cs8900_input: pbuf @%p len %u\n", q, q->len));	        ptr = q->payload;          // TODO: CHECK: what if q->len is odd? we don't use the last byte?	        for (i = 0; i < (q->len + 1) / 2; i++)      	  {	          *ptr = RXTXREG;	          ptr++;      	  }      	}      }      // could not allocate a pbuf      else      {        // skip received frame        // TODO: maybe do not skip the frame at this point in time?//	Put_String("cs8900: pbuf error\n");//   Put_String("cs8900: pack len=");// 	mprintf(len,6,0); // 	mprintf(stats.pbuf.used,6,0);        PACKETPP = CS_PP_RXCFG;        PPDATA = (0x0003U | 0x0100U/*RxOKiE*/ | 0x0040U/*Skip_1*/);#if (CS8900_STATS > 0)        ((struct cs8900if *)netif->state)->dropped++;#endif        len = 0;      }    }    // length was zero    else    {    }  }  return p;}// To be called when the cs8900a needs service. Does// not assume the cs8900a needs service. Does test the

⌨️ 快捷键说明

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