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

📄 lan91c111.c

📁 motorola 针对coldfire 5275 评估板的Dbug bootloader源程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * File:        lan91c11.c
 * Purpose:     Device driver for the SMSC LAN91C111
 *
 * Notes:       
 *
 */

#include "src/include/dbug.h"
#include "src/uif/net/net.h"
#include "src/include/dev/lan91c111.h"

/********************************************************************/

static int  lan91c111_reset (NIF *);
static void lan91c111_start (NIF *);
static void lan91c111_stop (NIF *);
static int  lan91c111_send (NIF *, HWA_ADDR_P, HWA_ADDR_P, uint16, NBUF*);
static void lan91c111_receive (void *, NIF *);
static uint16 lan91c111_read_phy_reg(uint8, uint8);
static void lan91c111_write_phy_reg(uint8, uint8, uint16);
static void lan91c111_phy_configure(void);
static void lan91c111_phy_shutdown(void);



/********************************************************************/
int
lan91c111_init (NIF *nif, int vector)
{
    nif_init(nif, "lan91c111");
    nif->vector = vector;

    nif->hwa_size = 6;
    nif->mtu = 1500;
    nif->reset = lan91c111_reset;
    nif->start = lan91c111_start;
    nif->stop = lan91c111_stop;
    nif->send = lan91c111_send;
    nif->receive = (void *)&lan91c111_receive;
    nif->rx_alloc = nbuf_rx_allocate;
    nif->tx_alloc = nbuf_tx_allocate;
    nif->rx_free = nbuf_rx_release;
    nif->tx_free = nbuf_tx_release;
    return TRUE;
}

/********************************************************************/
static int
lan91c111_reset (NIF *nif)
{
    int i;
    (void)nif;

    /* This resets the registers mostly to defaults, but doesn't
       affect EEPROM.  That seems unnecessary */
    SMC_SELECT_BANK(0);
    LAN91C111_RCR = LAN91C111_RCR_SOFTRST;

    /* Setup the Configuration Register */
    /* This is necessary because the CONFIG_REG is not affected */
    /* by a soft reset */

    SMC_SELECT_BANK(1);
    LAN91C111_CFGR |= LAN91C111_CFGR_DEFAULT;

    SMC_SELECT_BANK(0);

    /* this should pause enough for the chip to be happy */
    for( i=0 ; i < 10000; i++);

    /* Disable transmit and receive functionality */
    LAN91C111_RCR = LAN91C111_RCR_CLEAR;
    LAN91C111_TCR = LAN91C111_TCR_CLEAR;

    /* set the control register to automatically
       release successfully transmitted packets, to make the best
       use out of our limited memory */
    SMC_SELECT_BANK(1);
    LAN91C111_CTRLR |= LAN91C111_CTRLR_AUTO_RELEASE;

    /* Reset the MMU */
    SMC_SELECT_BANK(2);
    LAN91C111_MMCR = LAN91C111_MMCR_RESET;
    while (LAN91C111_MMCR & LAN91C111_MMCR_BUSY);

    /* Disable all interrupts */
    LAN91C111_IMR = 0;

    return TRUE;
}

/********************************************************************/
static void
lan91c111_start (NIF *nif)
{
    /* Configure the Phy */
    lan91c111_phy_configure();

    /* now, enable interrupts */
    SMC_SELECT_BANK(2);
    LAN91C111_IMR = (LAN91C111_IMR_RCV_INT | LAN91C111_IMR_TX_INT);

    SMC_SELECT_BANK(0);
    /* see the header file for options in TCR/RCR DEFAULT*/

    /* enable transmit and recieve */
    LAN91C111_RCR = LAN91C111_RCR_DEFAULT;
    LAN91C111_TCR = LAN91C111_TCR_DEFAULT;

    /* Set Hardware Address */
    SMC_SELECT_BANK(1);
    LAN91C111_IAR01 = (uint16)(((nif->hwa[0])<<8) | nif->hwa[1]);
    LAN91C111_IAR23 = (uint16)(((nif->hwa[2])<<8) | nif->hwa[3]);
    LAN91C111_IAR45 = (uint16)(((nif->hwa[4])<<8) | nif->hwa[5]);
}

/********************************************************************/
static void
lan91c111_stop (NIF *nif)
{
    (void)nif;
    
    SMC_SELECT_BANK(0);

    /* Disable transmit and receive functionality */
    LAN91C111_RCR = LAN91C111_RCR_CLEAR;
    LAN91C111_TCR = LAN91C111_TCR_CLEAR;

    /* Shutdown Phy */
    lan91c111_phy_shutdown();
}

/********************************************************************/
static int
lan91c111_send (NIF *nif,
    HWA_ADDR_P  eth_dest,
    HWA_ADDR_P  eth_src,
    uint16      eth_type,
    NBUF        *pNbuf)
{
    /*
     * This routine transmits one frame.  This routine only accepts
     * 6-byte Ethernet addresses.
     */
    uint32 mod_data_length, index, success, timeout, j;
    uint16 numPages, isr;

    /*
     * The format of an Ethernet frame looks like:
     *
     *   00 01 02 03 04 05
     *  +--+--+--+--+--+--+
     *  |  |  |  |  |  |  | destination ethernet address
     *  +--+--+--+--+--+--+
     *   06 07 08 09 0A 0B
     *  +--+--+--+--+--+--+
     *  |  |  |  |  |  |  | source ethernet address
     *  +--+--+--+--+--+--+
     *   0C 0D
     *  +--+--+
     *  |  |  | type (IP = 0x0800)
     *  +--+--+
     *   0E 0F ...
     *  +--+--+--+--+--+--+
     *  |  |  |  |  |  |  | data (min of 46 octets, max of 1500)
     *  +--+--+--+--+--+--+
     *
     *  +--+--+--+--+
     *  |  |  |  |  | 32-bit CRC (generated by hardware)
     *  +--+--+--+--+
     *
     * NOTE:  The NS8390 takes care of pre-amble, and is programmed
     * to generate the 32-bit CRC.
     *
     * NOTE:  The minimum size of data transmitted in an ethernet
     * frame is 46 octets (bytes).
     */

    /*
     * Check for valid length of data.
     */
    if ((pNbuf->length > nif->mtu) || (pNbuf->length <= 0))
        return 0;

    /* 
     * Modify Data Length if necessary 
     */
    mod_data_length = pNbuf->length;

    /* 
     * Align data length to 16-bits 
     */
    if (mod_data_length & 0x0001)
        ++mod_data_length;

    /* 
     * Verify data length >= minimum Ethernet packet size 
     */
    if (mod_data_length < ETH_MIN_SIZE)
        mod_data_length = ETH_MIN_SIZE;

    /*
     * During the course of loading a frame into the FIFO, we
     * can not have interrupts occur, especially those from the
     * receiver!
     */
    board_irq_disable();

    /* 
     * Allocate memory for TX 
     */
    SMC_SELECT_BANK(2);
    numPages = (uint16)(mod_data_length >> 8);
    
    if (numPages > 7 )  /* Too big */
        return FALSE;

    LAN91C111_MMCR = (uint16)(LAN91C111_MMCR_ALLOC | (numPages <<8));
    while (LAN91C111_MMCR & LAN91C111_MMCR_BUSY)
        ;
    
    /* 
     * Wait for allocation to complete 
     */
    timeout = 100; 

    do {
        isr = LAN91C111_ISR;
        if (isr & LAN91C111_ISR_ALLOC_INT)
            {
            // allocation complete
            LAN91C111_ISR = (isr & 0x00FF) | LAN91C111_ISR_ALLOC_INT;
            break;
            }

        /* delay some time */
        for( j=0 ; j<100 ; j++);

    } while ( -- timeout );

    if (timeout < 1)
        {
        printf("SMSC MMU memory allocation timeout");
        return FALSE;
        }
    
    /* 
     * Copy the TX packet number into the Packet Number Register 
     */
    LAN91C111_PNR = (uint16)((LAN91C111_ARR & 0x3F)<<8);

    /* 
     * Check to see if FIFO is emtpy 
     */
    if(LAN91C111_PTR & LAN91C111_PTR_NOT_EMPTY)
    {
        return FALSE;
    }

    /* 
     * Write the Pointer Register 
     */
    LAN91C111_PTR = LAN91C111_PTR_AUTOINC;

    /* 
     * Write status word  to Data area
     */
    LAN91C111_DATA = 0x0000;

    /* 
     * Write Byte count 
     */
    LAN91C111_DATA = (uint16)UBLBSWTICH(mod_data_length + 20);

    /*
     * Write destination ethernet address 
     */
    LAN91C111_DATA = *((uint16 *)&eth_dest[0]);
    LAN91C111_DATA = *((uint16 *)&eth_dest[2]);
    LAN91C111_DATA = *((uint16 *)&eth_dest[4]);

    /* 
     * Write source ethernet address 
     */
    LAN91C111_DATA = *((uint16 *)&eth_src[0]);
    LAN91C111_DATA = *((uint16 *)&eth_src[2]);
    LAN91C111_DATA = *((uint16 *)&eth_src[4]);

    /* 
     * Write type 
     */
    LAN91C111_DATA = eth_type;

    /* 
     * Write data 
     */
    for (index = 0; (index + 1) < pNbuf->length; index += 2)
    {
        LAN91C111_DATA = *((uint16*)&pNbuf->data[ETH_HDR_SIZE +index]);
    }

    /* 
     * Write odd byte and pad with an extra byte to maintain 16-bit alignment 
     */
    if(pNbuf->length & 0x0001)
    {
        LAN91C111_DATA = (uint16)(pNbuf->data[ETH_HDR_SIZE + pNbuf->length - 1] << 8);
        ++pNbuf->length;
    }

    /* 
     * Pad with 0x00's if original size was less than ETH_MIN_SIZE 
     */
    for(index=pNbuf->length; index < ETH_MIN_SIZE; index += 2)
        LAN91C111_DATA = 0;

    /* 
     * Write control byte - already aligned to always be even 
     */
    LAN91C111_DATA = 0x0010;

    /* 
     * Issus "ENQUEUE PACKET NUMBER TO TX FIFO 
     */
    LAN91C111_MMCR = LAN91C111_MMCR_ENQUEUE;
    while (LAN91C111_MMCR & LAN91C111_MMCR_BUSY)
        ;

    /* 
     * Free the network buffer 
     */
    nif->tx_free(pNbuf);

    /* 
     * Allow interrupts again 
     */
    board_irq_enable();

    return TRUE;
}

/********************************************************************/
static void
lan91c111_receive (void *not_used, NIF *nif)
{
    uint16 pktnum;
    uint16 pktlength;
    uint16 status;
    uint16 lastword;
    uint32 index;
    eth_frame_hdr * ethframe;
    NBUF * pNbuf;

    (void)not_used;
    
    /* I should already be in BANK 2 */
    pktnum = LAN91C111_RXFIFOR;

    if ( pktnum & LAN91C111_RXFIFOR_REMPTY ) 
    {
        /* we got called , but nothing was on the FIFO */
        /* don't need to restore anything */
        return;
    }

    /* Check to see if FIFO is emtpy */
    if(LAN91C111_PTR & LAN91C111_PTR_NOT_EMPTY)
    {
        printf("FIFO is NOT EMPTY\n");
        return;
    }

    /* Write Addr Ptr */
    /* Write Address Pointer Reg */
    LAN91C111_PTR = (LAN91C111_PTR_AUTOINC | LAN91C111_PTR_RCV |LAN91C111_PTR_READ);

    /* Read Word 0 from RAM */

    /* First two words are status and packet_length */
    status      = LAN91C111_DATA;
    pktlength   = LAN91C111_DATA;
    pktlength   = (uint16)(UBLBSWTICH(pktlength) & 0x07FF);

    /* Status work ok? */
    if(status & RS_ERRORS)
    {
        printf("error in receive status word: %04X\n",status);
    }

    /* check if multicast*/
    if((status & RS_MULTICAST) | (status & RS_BRODCAST))
    {   
        /* Issue "Remove and Release" command */
        while (LAN91C111_MMCR & LAN91C111_MMCR_BUSY);
        LAN91C111_MMCR = LAN91C111_MMCR_RELEASE;
        return;
    }

    /* Obtain system RAM buffer for the frame */
    if ((pNbuf = nif->rx_alloc()) == NULL)
    {
        printf("error, cannot obtain system RAM buffer for the frame\n");
        /* Issue "Remove and Release" command */        
        while (LAN91C111_MMCR & LAN91C111_MMCR_BUSY);
        LAN91C111_MMCR = LAN91C111_MMCR_RELEASE;
        return;
    }

    ethframe = (eth_frame_hdr *)&pNbuf->data[ETH_HDR_OFFSET];

    /* Copy Data Per upper Layer Specs */

    /* get destination */
    *(uint16*)&ethframe->dest[0] = LAN91C111_DATA;
    *(uint16*)&ethframe->dest[2] = LAN91C111_DATA;
    *(uint16*)&ethframe->dest[4] = LAN91C111_DATA;
    /* get source */
    *(uint16*)&ethframe->src[0] = LAN91C111_DATA;
    *(uint16*)&ethframe->src[2] = LAN91C111_DATA;
    *(uint16*)&ethframe->src[4] = LAN91C111_DATA;
    /* get frame type */
    ethframe->type = LAN91C111_DATA;

    /* check if we can handle this type */
    if(!nif_protocol_exist(nif, ethframe->type))
    {
        /* Issue "Remove and Release" command */
        printf("can't handle this frame\n");
        while (LAN91C111_MMCR & LAN91C111_MMCR_BUSY);
        LAN91C111_MMCR = LAN91C111_MMCR_RELEASE;

        nif->rx_free(pNbuf);
        return;
    }

    /* Get length of data in frame */
    /* 6 for des address  */
    /* 6 for src address  */
    /* 2 for type         */
    /* 6 for SMSC frame (status word, byte count, control byte and odd byte) */

    pNbuf->length = pktlength - (6+6+2+6);

⌨️ 快捷键说明

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