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

📄 cs8900_enet_if_driver.c

📁 sharp的arm920t 7A400的评估板附带光盘Sharp KEVLH7A400 v0.3b Welcome to the SHARP KEV7A400 Evaluation board
💻 C
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************
 *  $Workfile:   CS8900_enet_if_driver.c  $
 *  $Revision:   1.1  $
 *  $Author:   MaysR  $
 *  $Date:   Aug 29 2002 08:57:52  $
 *
 *	Project: General ethernet driver for CS8900A
 *
 *  Description:  This file contains functions to perform the following:
 *        Initialization of the CS8900A ethernet controller
 *        Responds to ethernet interrupts
 *        Provides read data to another process
 *        Initiates transfer of data packets
 *
 *  References: CS8900 Datasheet
 *
 *  Notes:  The user must provide the 3 functions listed as extern's
 *          at the top of this file.  These functions are platform 
 *          dependent.
 * 
 *	Revision History:
 *  $Log:   //smaicnt2/pvcs/VM/CHIPS/archives/LH7A400/Ethernet/Drivers/CS8900_enet_if_driver.c-arc  $
 * 
 *    Rev 1.1   Aug 29 2002 08:57:52   MaysR
 * Corrected parameter types for set IRQ and set DMA functions.
 * 
 *    Rev 1.0   Aug 27 2002 11:41:04   MaysR
 * Initial revision.
 * 
 *
 * SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
 * OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
 * AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES, 
 * SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
 *
 * SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY 
 * FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A 
 * SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
 * FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
 *
 *	COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
 *		CAMAS, WA
 *
 ****************************************************************************/

#include <stdio.h>
#include "CS8900_enet_if_driver.h"
#include "CS8900_enet_eeprom_driver.h"

extern void enet_int_init(void);
extern void enet_int_clear(void);
extern void enet_if_wakeup(void);
extern void enet_if_mem_init(void);
extern void dummy_write(void);
extern UNS_16 * const enet_port_addr[];
extern UNS_32 dummy_write_en;


/*
 This is a pointer to a memory mapped PacketPage structure at
 address 0x0. Don't try to access the pointer at that address or
 the system may crash. However, the offsets used for the port I/O
 mapping functions can be used with the address attribute.
*/
enet_pp_t *enet_pp_data = (void *) 0x0;

// Local copy of the ethernet controller address
UNS_8 enetaddr [6];

// Number of RX and TX buffers. Each RX and TX buffer is allocated
// 1550 bytes in memory
#define NUM_BUFS 4

// Message queue structure
typedef struct
{
    INT_32 messages_queued;     // Number of packets queued (sb atomic)
    INT_32 next_message_in;     // Index into next packet in
    INT_32 next_message_out;    // Index into next packet out
    buffer_t buffer [NUM_BUFS]; // Buffers
    INT_32 psize [NUM_BUFS];    // Size of the packet
} queue_t;

// Message queues
queue_t tx, rx;

// Transmit on flag, used to indicate if the transmitter is available
// to transfer data
INT_32 enet_txon;

/*****************************************************************************
 * Main functions - initialization
 ****************************************************************************/

/**********************************************************************
*
* Function: enet_init
*
* Purpose:  Initialize the CS8900 Ethernet controller.
*  
* Processing:
*   The function configures the CS8900 Ethernet controller. The 
*   configuration is very basic. Interrupts are generated for
*   TX and RX message frames only. All other interrupts are disabled.
*   The SMA_priority driver is used to route the ethernet interrupt 
*   when it occurs.  The SMA_priority driver should be initialized and 
*   interrupts enabled prior to using this initialization service.
*
* Parameters:  None
*
* Outputs:  None
*
* Returns:  '0' if the initialization was successful, 
*           '1' if the chip ID was not found,
*           '2' if the EEPROM was not valid.
*
* Notes:
*   This driver requires that the external interrupt source be set to
*   'level high active' mode. Using the edge triggered mode may cause
*   interrupts to be missed.
*
**********************************************************************/
INT_32 enet_init (void)
{
    UNS_16 volatile temp;

   // Initialize chip memory interface and disable sleep signal
    enet_if_mem_init ();
    enet_if_wakeup ();

// The CS8900 requires the nSBHE line to toggle once after reset.
    dummy_write();

/*
 * Verify that CS8900A controller exists, return an error status if it 
 * is not found.  The CS8900A ISA registration number is 0x0E, 0x63 at 
 * PacketPage address 0x0.  This will be read if the controller exists.
 */
    enet_set_pp_addr (&enet_pp_data->bus_regs.chip_id_h, 1);
    if (enet_read_data () != 0x630E)
    {
        return (1);
    }

// DISABLED - EEPROM_OK bit not active, but address was loaded!
   // Verify that the ethernet controller address was loaded from
   // the EEPROM. (Actually, this service just verifies that any data
   // in the EEPROM was loaded correctly).
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg16_selfst, 0);
    if ((enet_read_data() & EEOK) == 0)
    {
      // EEPROM data was invalid or non-existant, no default MAC 
      // address was available for the ethernet controller
        return (2);
    }

//Need to init EEPROM structure with data from chip at this point!!


   // Before starting with the configuration, disable the receiver
   // and transmitter
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg13_linectl, 0);
    enet_write_data (RLINECTL | AUTOAUI);

   // Disable ethernet controller DMA
    enet_set_dma_chan(DMA_NONE);

   // Set memory base address to 0x0 (mode not used in this driver)
    enet_set_pp_addr (&enet_pp_data->bus_regs.mem_base_h, 1);
    enet_write_data (0x0);      // High half of word
    enet_write_data (0x0);      // Low half of word
    enet_8900e2_set_io(0x0);

   // Set boot PROM address and size to 0x0 (not used)
    enet_set_pp_addr (&enet_pp_data->bus_regs.boot_pr_addr_h, 1);
    enet_write_data (0x0);      // High half of boot PROM address
    enet_write_data (0x0);      // Low half of boot PROM address
    enet_write_data (0x0);      // High half of boot PROM mask (size)
    enet_write_data (0x0);      // Low half of boot PROM mask (size)

   // Configure the receiver
   //    No DMA
   //    Interrupt on good RX frames only
   //    No support for short or long frames
   //    Do not include CRC in buffer
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg3_rxcfg, 0);
    enet_write_data (RRXCFG | RXOKIE);

   // Setup receiver control
   //    Accept no other frames besides IA frames
   //    Accept on valid RX frames
   //    Do not accept short or long frames
   //    Do not accept frames with a CRC error
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg5_rxctl, 0);
    enet_write_data (RRXCTL | RXOKA | INDIVIDUALA);

   // Configure the transmitter
   //    Interrupt generated on completion of TX interrupt
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg7_txcfg, 0);
    enet_write_data (RTXCFG | TXOKIE);

   // Configure the buffers
   //    Interrupt ONLY when ready to transfer a new packet
    enet_set_pp_addr (&enet_pp_data->stco_regs.regb_bufcfg, 0);

#ifdef IRQACTIVE
    enet_write_data (RBUFCFG | RDY4TXIE);

#else
   // Setup for polling mode
    enet_write_data (RBUFCFG);
#endif

   // Configure self control
   //    No support for hardware power modes
   //    Status LEDS are active
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg15_selfctl, 0);
    enet_write_data (RSELFCTL);

   // Configure bus control
   //    Disable memory mode and IOCHRDY
   //    Enable interrupts
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg17_busctl, 0);
#ifdef IRQACTIVE
    enet_write_data (RBUSCTL | ENABLERQ);
#else
    enet_write_data (RBUSCTL);
#endif

   // Configure test control
   //    No test modes are enabled
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg19_testctl, 0);
    enet_write_data (RTESTCTL);

   // Clear hash filter, not used
    enet_set_pp_addr (&enet_pp_data->filter_regs.hash_filter, 1);
    enet_write_data (0x0);
    enet_write_data (0x0);
    enet_write_data (0x0);
    enet_write_data (0x0);

   // Get local copy of ethernet controller address. This should
   // of been loaded from the EEPROM at reset
    enet_get_address (enetaddr);

   // Setup interrupt line INTR0 as the active interrupt. The
   // ethernet interrupt is active high and must be configued.
    enet_set_irq_number(INTR0);

   // Clear any pending interrupts and all messages from controller
    temp = 1;
    while (temp != 0)
    {
      // Read status queue until all interrupts have been cleared
        temp = enet_read_port (isq);
    }
    enet_int_init();

   // Initialize queue structures
    tx.messages_queued  = 0;
    tx.next_message_in  = 0;
    tx.next_message_out = 0;
    rx.messages_queued  = 0;
    rx.next_message_in  = 0;
    rx.next_message_out = 0;

    // Transmitter initially idle
    enet_txon = 0;

   // The ethernet transceiver is not enabled as part of this function
    return 0;
}

/**********************************************************************
*
* Function: enet_disable_transceiver
*
* Purpose:  Disable the ethernet receiver and transmitter.
*  
* Processing:  The ethernet transceiver is disabled.
*
* Parameters:  None
*
* Outputs:  None
*
* Returns:  Nothing
*
* Notes:  None
*
*
**********************************************************************/
void enet_disable_transceiver (void)
{
   // Disable receiver and transmitter
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg13_linectl, 0);
    enet_write_data (RLINECTL | AUTOAUI);
}

/**********************************************************************
*
* Function: enet_enable_transceiver
*
* Purpose:  Enable the ethernet receiver and transmitter.
*  
* Processing:  The ethernet transceiver is enabled.
*
* Parameters:  None
*
* Outputs:  None
*
* Returns:  Nothing
*
* Notes:  None
*
**********************************************************************/
void enet_enable_transceiver (void)
{
   // Enable receiver and transmitter
    enet_set_pp_addr (&enet_pp_data->stco_regs.reg13_linectl, 0);
    enet_write_data (RLINECTL | AUTOAUI | SERRXON | SERTXON);
}

/*****************************************************************************
 * Main functions - Interrupt handling
 ****************************************************************************/

/**********************************************************************
*
* Function: enet_rx_event
*
* Purpose:  Ethernet receive event interrupt handler
*  
* Processing:
*	The receive event will occur when an ethernet packet is received
*   with no errors and has passed the address filters. The packet is
*   extracted from the ethernet controller into the rx message queues
*   and awaits processing from background tasks.
*
* Parameters:
*	status:    Status word read from interrupt handler entry
*
* Outputs:  None
*
* Returns:  Nothing
*
* Notes:  None
*
**********************************************************************/
void enet_rx_event (UNS_16 status)
{
    INT_32 mlen;

   // Is any buffer space available
    if (rx.messages_queued < NUM_BUFS)
    {
      // Space exists for the message, check the status
        if ((status & RXOK) == RXOK)
        {
         // Last message received was valid, process it
         // Read the length of the message in bytes
            enet_set_pp_addr (&enet_pp_data->frame_regs.rxlen, 1);
            mlen = (INT_32) enet_read_data ();

         // If the byte count is odd, add a single byte to it (needed
         // to make sure all 'bytes' are read from a half-word interface)
         // Convert the count to a word count
            mlen = (mlen + (mlen & 0x1)) / 2;

         // Copy the packet from the controller to the buffer
            enet_read_block ((UNS_16 *) &rx.buffer [rx.next_message_in],
                             mlen);

         // Save length of message (in bytes)
            rx.psize [rx.next_message_in] = mlen << 1;

         // Setup next message queue pointer
            rx.next_message_in++;
            if (rx.next_message_in >= NUM_BUFS)
            {
                rx.next_message_in = 0;
            }

         // Increment number of queued RX messages
            rx.messages_queued++;
        }
    }
}

/**********************************************************************
*
* Function: enet_tx_event
*
* Purpose:  Ethernet transmit event interrupt handler
*  
* Processing:  Neesd
*
* Parameters:
*	status:    Status word read from interrupt handler entry
*
* Outputs:  None
*
* Returns:  Nothing
*
* Notes:  None
*
**********************************************************************/
void enet_tx_event (UNS_16 status)
{
   // Check to see if transfer completed ok
    if ((status & TXOK) == TXOK)
    {
      // Transfer completed OK, do nothing
        ;
    }
}

/**********************************************************************
*
* Function: enet_buf_event
*
* Purpose:  Ethernet buffer event interrupt handler
*  
* Processing:
*
* Parameters:
*	status:    Status word read from interrupt handler entry
*
* Outputs:  None
*
* Returns:  Nothing
*
* Notes:
*
**********************************************************************/
void enet_buf_event (UNS_16 status)
{
   // Is controller ready to transmit data?
    if ((status & RDY4TX) == RDY4TX)
    {
      // Transmitter is idle
        enet_txon = 0;
    }

   // Are any more packets ready to send?
    if (tx.messages_queued > 0)
    {
      // Another packet is waiting, transfer it if idle
        if (enet_txon == 0)
        {
         // Send next message in queue
            enet_send_packet ((char *) &tx.buffer [tx.next_message_out],
                              tx.psize [tx.next_message_out]);

         // Lower queued message count
            tx.messages_queued--;
 
          // Remove sent message from queue
            tx.next_message_out++;
            if (tx.next_message_out > NUM_BUFS)
            {
                tx.next_message_out = 0;
            }

         // Transmitter is now on
            enet_txon = 1;         
        }
    }
}

/**********************************************************************
*
* Function: enet_isr
*
* Purpose:  Ethernet Transmit/Receive interrupt.
*  
* Processing:
*	This functions services the ethernet controller when an interrupt
*   is generated by the controller. Interrupts are broken into three
*   different types: Receive (RX), Transmit (TX), and Other. Receive
*   interrupts occur when an ethernet packet for the selected card (or
*   broadcast) address is received. Transmit interrupts occur when a
*   packet is ready to be sent. Other interrupts are not supported
*   by this driver.
*
* Parameters:  None
*
* Outputs:  None
*
* Returns:  Nothing
*

⌨️ 快捷键说明

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