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

📄 lan91c111.c

📁 Coldfire MCF5282 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 + -