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

📄 ether_cs8900.c

📁 Embeded bootloader (rrload by ridgerun) for TI linux based platform v5.36
💻 C
字号:
/* * File: cs8900.c * * This is an implementation of a ether.h interface. This implementation * supplies an ethernet driver particular to the CS8900 series ethernet chip * set. This h/w dependent implemenation exposes the h/w independent ether.h * interface. *  * Implemented with assitance from the Cirrus Logic CS8900A h/w data sheet. * * See Also *   ether.h * * Copyright (C) 2002 RidgeRun, Inc. * Author: RidgeRun, Inc  <skranz@ridgerun.com> * *  This program is free software; you can redistribute  it and/or modify it *  under  the terms of  the GNU General  Public License as published by the *  Free Software Foundation;  either version 2 of the  License, or (at your *  option) any later version. * *  THIS  SOFTWARE  IS  PROVIDED  ``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 AUTHOR  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. * *  You should have received a copy of the  GNU General Public License along *  with this program; if not, write  to the Free Software Foundation, Inc., *  675 Mass Ave, Cambridge, MA 02139, USA. * * Please report all bugs/problems to the author or <support@dsplinux.net> * * key: RRGPLCR (do not remove) * */#include "memconfig.h"#include "types.h"#include "util.h"#include "ether.h"#include "net.h"#include "io.h"#define RECVPORT   0x0000 // Recive Data Port.#define XMITPORT   0x0000 // Transmit Data Port.#define TXCMDPORT  0x0004 // TxCMD (Transmit Command)#define TXLENPORT  0x0006 // TxLength (Transmit Length)#define INTSTATQUE 0x0008 // Interrupt Status Que.#define ADD_PORT   0x000A // PacketPage Pointer port.#define DATA_PORT  0x000C // PacketPage Data port.#define INTCNTRL   0x0022#define RECVCONF   0x0102#define RECVCNTRL  0x0104#define XMITCONF   0x0106#define BUFFCONF   0x010A#define LINECNTRL  0x0112#define SELFCNTRL  0x0114#define BUSCNTRL   0x0116#define RECVEVENT  0x0124 // register 4#define XMITEVENT  0x0128#define SELFSTATUS 0x0136#define BUSSTATUS  0x0138#define MACREG1    0x0158#define MACREG2    0x015A#define MACREG3    0x015C#define RXSTATUS   0x0400#define RXLENGTH   0x0402#ifdef BSPCONF_BTLDR_CS8900_DEBUGstatic unsigned short last_readreg_addr, last_readreg_data;#endif/****************************** Routine: Description: ******************************/static __inline__ void outw(unsigned short reg_offset, unsigned short val){  *((volatile unsigned short *)(BSPCONF_ETHERNET_BASE+reg_offset)) = val;}  /****************************** Routine: Description: ******************************/static __inline__ unsigned short inw(unsigned short reg_offset){  return *((volatile unsigned short *)(BSPCONF_ETHERNET_BASE+reg_offset));}/****************************** Routine: Description: ******************************/static void __inline__ outb(unsigned short reg_offset, unsigned char val){  *((volatile unsigned char *)(reg_offset+BSPCONF_ETHERNET_BASE)) = val;}  /****************************** Routine: Description: ******************************/static __inline__ unsigned char inb(unsigned short reg_offset){  return *((volatile unsigned char *)(reg_offset+BSPCONF_ETHERNET_BASE));}/****************************** Routine: Description: ******************************/static __inline__ void insw(unsigned short port, void* buf, unsigned int count){  register unsigned short* wbuf = (unsigned short*) buf;  while(count--)    *wbuf++  = inw(port);}/****************************** Routine: Description: ******************************/static __inline__ void outsw(unsigned short port, const void* buf, unsigned int count){  register const unsigned short* wbuf = (const unsigned short*) buf;  while(count--)    outw(port,*wbuf++);}/****************************** Routine: Description: ******************************/static void writereg(unsigned short reg_offset, unsigned short val){#ifdef BSPCONF_BTLDR_CS8900_DEBUG  util_printf("writereg: %x = %x \n", reg_offset, val);#endif  outw(ADD_PORT,reg_offset);  outw(DATA_PORT,val);}/****************************** Routine: Description: ******************************/#ifdef BSPCONF_BTLDR_CS8900_DEBUGunsigned short readreg_silent(unsigned short reg_offset){  outw(ADD_PORT,reg_offset);  return(inw(DATA_PORT));}#endif/****************************** Routine: Description: ******************************/unsigned short readreg(unsigned short reg_offset){#ifdef BSPCONF_BTLDR_CS8900_DEBUG  unsigned short i;  outw(ADD_PORT,reg_offset);  i=inw(DATA_PORT);  if ( ( last_readreg_addr != reg_offset ) ||       ( last_readreg_data != i ) )  {    util_printf(" readreg: %x = %x \n", reg_offset, i);    last_readreg_addr = reg_offset;    last_readreg_data = i;  }  return(i);#else  outw(ADD_PORT,reg_offset);  return(inw(DATA_PORT));#endif}/****************************** Routine: Description: ******************************/static void chip_online(void){  // Next, put the chip on-line with the wire.  writereg(LINECNTRL,0x0000);  writereg(INTCNTRL,0x0000);  writereg(BUFFCONF,0x3300);  writereg(BUSCNTRL,0x0000);    writereg(RECVCNTRL,0x0D00);  writereg(RECVCONF,0x1100);  writereg(LINECNTRL,0x00D3);}/****************************** Routine: Description: ******************************/#if 0static void chip_offline(void){  // Next, take the chip off-line from the wire.  writereg(LINECNTRL,0x0000);}#endif/****************************** Routine: Description: ******************************/static void chip_reset(void){#ifdef BSPCONF_BTLDR_CS8900_DEBUG   last_readreg_addr=0;  last_readreg_data=0;#endif  writereg(LINECNTRL,0x0000);  // go offline  writereg(SELFCNTRL,0x0055);  // reset.  while (!(readreg(SELFSTATUS)&0x0080)) {          ; //wait  }}/****************************** Routine: Description: ******************************/static void chip_mac_assign(unsigned char *mac_array){  short s;  s = mac_array[0] | (mac_array[1] << 8);  writereg(MACREG1,s);  s = mac_array[2] | (mac_array[3] << 8);  writereg(MACREG2,s);  s = mac_array[4] | (mac_array[5] << 8);  writereg(MACREG3,s);}/****************************** Routine: Description:   Polls the chip until a chip packet is recieved   containing an ether frame and then xfers the data   field portion of the received ether frame to the   client's supplied datagram buffer and then sets the   client's num_bytes variable appropriately. ******************************/static void chip_read_data_polled(void *datagram,            // in/out                                  unsigned short *num_bytes) // in/out{  #define RxOK 0x0100  #define RxBROADCAST 0x0800  unsigned short i;  unsigned short RxStatus, RxLength;  while (1) {    while (1) {      // loop here until the bit goes high indicating      // that the chip has a non broadcast incoming packet for us.      i=readreg(RECVEVENT);      if ((i & RxOK) && ! (i & RxBROADCAST)) {	break;      }    }#ifdef BSPCONF_BTLDR_CS8900_DEBUG    util_printf("received a packet \n");#endif    // Next, repeatively read from the receive port to    // pick up the packet; the packet is actually proceeded    // by a status word and a length word, the same two    // words that would also be returned from a readreg(RXSTATUS)    // and readreg(RXLENGTH), but we might as well get them this    // way instead:    RxStatus = inw(RECVPORT);    RxLength = inw(RECVPORT);    if (RxStatus & 0x7080) {      // Error: Either the Extradata, Runt, CRCerror, or Dribble bit was set.      // Ignore this packet and loop back around to pick up another.    }    else {      // --Normal Path--      // First read out the ether header that proceeds the frame data field. We'll      // temporarily put this in the client's buffer and then immediately overwrite      // it with the frame data field that we really want to deliver to the client.      insw(RECVPORT, (unsigned short *)datagram, (sizeof(ether_hdr_t)>>1));      if (RxLength > sizeof(ether_hdr_t)) { // sanity check        // --Normal Path--        RxLength -= sizeof(ether_hdr_t); // adjust length to reflect data field only.        // Now load the client's buffer with the frame's data field.         insw(RECVPORT, (unsigned short *)datagram, RxLength>>1);        if (RxLength & 1) {          // Odd length; get that last byte.          ((unsigned char *)datagram)[RxLength-1] = (unsigned char)inw(RECVPORT);        }        *num_bytes = RxLength;#ifdef BSPCONF_BTLDR_CS8900_DEBUG	util_dump_memory((unsigned int) datagram, RxLength);#endif        break; // return to client      }    }  }}/****************************** Routine: Description:   Package up the client's datagram into an Ether frame   which is then loaded into the chip for transmission on    the physical wire. Note: wire collisions are handled   by the chip itself. ******************************/static void chip_send_data(submit_mode mode,          // in                           char *device_MAC,          // in                           char *server_MAC,          // in                           void *datagram,            // in/out                           unsigned short *num_bytes) // in/out{  #define TxMask 0x87C0    // All error bits plus the TkOK bit.  #define TxErrMask 0x84C0 // All error bits minus the TkOK bit.  #define TX_AFTER_381 0x0040  #define TX_AFTER_ALL 0x00C0  #define RDY_FOR_TX_NOW 0x0100  ether_hdr_t *ethdatagram;  unsigned short ethfrm_len, *data, status;  unsigned char d_MAC[6], s_MAC[6];  int i;  while (1) {    util_fill_MAC(d_MAC,device_MAC);    util_fill_MAC(s_MAC,server_MAC);    // Add the eth header.    // Recall that the client has provided the space for us to    // back the pointer up like this and add our header.    ethdatagram = (ether_hdr_t *)(datagram - sizeof(ether_hdr_t));    // Next, build the ether frame header.    // Notice that our header does not include the 8 byte preamble     // of alternating 1s and 0s since the chip will provide those    // bits automatically as part of interfacing with the wire.    // chip also does the crc generation for us and appends it to    // tail end of our data as it heads out the wire.    for (i=0; i<6; i++) {      ethdatagram->dest_addr[i] = s_MAC[i];      ethdatagram->src_addr[i] = d_MAC[i];    }    ethdatagram->frame_type = 0x0000; // IP code as per /etc/protocols    // Hmmm????    // well 0x0000 is what I thought it should be anyways, but as I    // trace other packets moving about the network I see that they    // use the value 0x8000 although I don't understand the signifcance    // of that just yet. In the meantime it does seem to work beter    // to use that value. so... override previous setting now...    ethdatagram->frame_type = htons(0x0800); // override, see comment above.    ethfrm_len = *num_bytes + sizeof(ether_hdr_t);    if (ethfrm_len < 61) {      // *debug*, Get to the bottom of this one.      // Special case, at the moment I can't get the chip to send      // out ether packets smaller than this minimum amount. If it      // drops below it then pad it and assume that the destination      // server will just ignore the extra bytes. I happen to know      // that Tftp servers do, for example.      ethfrm_len = 61;    }    data = (unsigned short *)ethdatagram;    // Initiate the Transmit#ifdef BSPCONF_BTLDR_CS8900_DEBUG    util_printf("sending a packet \n");    util_printf("buffer = 0x%X, len = 0x%x\n",data,ethfrm_len); // *revisit-skranz* temp only.    util_printf("sizeof ether_hdr_t = 0x%x\n",sizeof(ether_hdr_t)); // *revisit-skranz* temp only.    util_printf("sizeof ip_hdr_t = 0x%x\n",sizeof(ip_hdr_t)); // *revisit-skranz* temp only.    util_printf("sizeof udp_hdr_t = 0x%x\n",sizeof(udp_hdr_t)); // *revisit-skranz* temp only.#endif    status = readreg(XMITEVENT); // clear any existing xmit status bits before starting new xmit.    outw(TXCMDPORT,TX_AFTER_381);    outw(TXLENPORT,ethfrm_len);    while (0 == (readreg(BUSSTATUS) & RDY_FOR_TX_NOW)) {      // Wait here until the chip performs the internal chip      // mem allocation needed to hold our ether frame packet.    }#ifdef BSPCONF_BTLDR_CS8900_DEBUG    util_dump_memory((unsigned int) data, ethfrm_len);#endif    // on the wire she goes....    outsw(XMITPORT,data,(ethfrm_len+1)>>1);    status = readreg(XMITEVENT); // read new xmit status bits.    while (0 == (status & TxMask)) {      // Wait here until the chip performs the transmission.      // When complete, or if aborted, then at least one bit      // in TxMask set will go high.      status = readreg(XMITEVENT); // read new xmit status bits.    }    if (0 == (status & TxErrMask)) {      // It had completed without an error bits being set.      // We won't have to resend our packet. The only bit that      // must have been set is the TkOK; good.      break;    }#ifdef BSPCONF_BTLDR_CS8900_DEBUG    util_printf("Bad xmit attempting; status = 0x%x; retrying... \n",status);#endif  }}/****************************** Routine: Description:    See ether.h for more info. ******************************/void ether_init(void){//  chip_reset();  // TF 030630 - removed so chip isn't touched until                   // TFTP is used (which causes chip_reset to be called)}/****************************** Routine: Description:   See ether.h for more info. ******************************/void ether_submit(submit_mode mode,          // in                  char *device_MAC,          // in                  char *server_MAC,          // in                  void *datagram,            // in/out                  unsigned short *num_bytes) // in/out{  // --Stage one--  switch(mode) {    case SEND:    case SEND_AND_GET_REPLY:      chip_send_data(mode,       // in                     device_MAC, // in                     server_MAC, // in                     datagram,   // in                     num_bytes); // in      break;    case RECV:      // See "Stage two" below.      break;    case FLUSH:      {        unsigned char d_MAC[6];        util_fill_MAC(d_MAC,device_MAC);        chip_reset();        chip_mac_assign(d_MAC);        chip_online();      }      break;    default:      SYSTEM_FATAL("Logic Error");      break;  }  // --Stage two--  switch(mode) {    case RECV:    case SEND_AND_GET_REPLY:      chip_read_data_polled(datagram,   // out                            num_bytes); // out      break;    default:      break;  }}

⌨️ 快捷键说明

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