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

📄 drv_lan91c111.c

📁 91c111的驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	while (timeout--) {
		status = smc_read_phy_register (PHY_STAT_REG);
		if (status & PHY_STAT_ANEG_ACK) {
			/* auto-negotiate complete */
			break;
		}

		//smc_wait_ms (500);	/* wait 500 millisecs */
		OSTimeDly( OS_DELAY_TIME(dSYSTEM_TIME_520MS));
		/* Restart auto-negotiation if remote fault */
		if (status & PHY_STAT_REM_FLT) {

			OS_DEBUGF(DEV_91C111_DEBUG, ("%s:PHY remote fault detected\r\n",SMC_DEV_NAME));

			/* Restart auto-negotiation */
			OS_DEBUGF(DEV_91C111_DEBUG, ("%s:PHY restarting auto-negotiation\r\n",SMC_DEV_NAME));

			smc_write_phy_register (PHY_CNTL_REG,
						PHY_CNTL_ANEG_EN |
						PHY_CNTL_ANEG_RST |
						PHY_CNTL_SPEED |
						PHY_CNTL_DPLX);
		}
	}

	if (timeout < 1) {

		OS_DEBUGF(DEV_91C111_DEBUG, ("%s:PHY auto-negotiate timed out\r\n", SMC_DEV_NAME));		

		
	}

	/* Fail if we detected an auto-negotiate remote fault */
	if (status & PHY_STAT_REM_FLT) {

		OS_DEBUGF(DEV_91C111_DEBUG, ("%s:PHY remote fault detected\r\n", SMC_DEV_NAME));

		
	}

	/* Re-Configure the Receive/Phy Control register */
	SMC_outw (RPC_DEFAULT, RPC_REG);


}


/*
 * Open and Initialize the board
 *
 * Set up everything, reset the card, etc ..
 *
 */
static int smc_open (void)
{
	int i;

	
	/* reset the hardware */

	smc_reset ();
	smc_enable ();
	
	/* conservative setting (10Mbps, HalfDuplex, no AutoNeg.) */
	/* Configure the Receive/Phy Control register */
	smc_phy_configure ();
	
	SMC_SELECT_BANK (1);

	for (i = 0; i < 6; i += 2) 
	{
		INT16U address;

		address = smc_mac_addr[i + 1] << 8;
		address |= smc_mac_addr[i];
		SMC_outw (address, ADDR0_REG + i);
	}

	
	return 0;
}

INT32U eth_init (void)
{
	
	smc_open();
	return (0);

}
#if 0
static void print_packet (INT8U * buf, INT32U length)
{
 
	INT32U i;
	INT32U remainder;
	INT32U lines;
	char str[1024];
	char tmp[100];
	sprintf (str,"\r\nPacket of length %d \r\n", length);

	lines = length / 16;
	remainder = length % 16;

	for (i = 0; i < lines; i++) {
		INT32U cur;

		for (cur = 0; cur < 8; cur++) {
			INT8U a, b;

			a = *(buf++);
			b = *(buf++);
			sprintf (tmp,"%02x%02x ", a, b);
			strcat(str,tmp);
		}
		sprintf (tmp,"\r\n");
		strcat(str,tmp);
	}
	for (i = 0; i < remainder / 2; i++) {
		INT8U a, b;

		a = *(buf++);
		b = *(buf++);
		sprintf (tmp,"%02x%02x ", a, b);
		strcat(str,tmp);
	}
	sprintf (tmp,"\r\n");
	strcat(str,tmp);
	debug_printf("%s",str);

}
#endif 
/*-------------------------------------------------------------
 .
 . smc_rcv -  receive a packet from the card
 .
 . There is ( at least ) a packet waiting to be read from
 . chip-memory.
 .
 . o Read the status
 . o If an error, record it
 . o otherwise, read in the packet
 --------------------------------------------------------------
*/
static int smc_rcv(void)
{
	int	packet_number;
	INT16U	status;
	INT16U	packet_length;
	INT32U	is_error = 0;

	INT8U	saved_pnr;
	INT16U	saved_ptr;

	SMC_SELECT_BANK(2);
	/* save PTR and PTR registers */
	saved_pnr = SMC_inb( PN_REG );
	saved_ptr = SMC_inw( PTR_REG );

	packet_number = SMC_inw( RXFIFO_REG );

	if ( packet_number & RXFIFO_REMPTY ) {
		//SMC_outw (MC_FREEPKT, MMU_CMD_REG);
		return 0;
	}

	
	/*  start reading from the start of the packet */
	SMC_outw( PTR_READ | PTR_RCV | PTR_AUTOINC, PTR_REG );

	/* First two words are status and packet_length */

	status		= SMC_inw( SMC91111_DATA_REG );
	packet_length	= SMC_inw( SMC91111_DATA_REG );


	packet_length &= 0x07ff;  /* mask off top bits */

	OS_DEBUGF(DEV_91C111_DEBUG,("RCV: STATUS %4x LENGTH %4x\r\n", status, packet_length ));

	if ( !(status & RS_ERRORS ) ){
		/* Adjust for having already read the first two words */
		packet_length -= 4; /*4; */


		/* set odd length for bug in LAN91C111, */
		/* which never sets RS_ODDFRAME */
		/* TODO ? */



		OS_DEBUGF(DEV_91C111_DEBUG,(" Reading %d words and %d byte(s) \r\n",(packet_length >> 1 ), packet_length & 1 ));

		SMC_insw(SMC91111_DATA_REG , RxPackets, packet_length >> 1);

		OS_DEBUGF(DEV_91C111_DEBUG,("Receiving Packet\r\n"));
		//print_packet( RxPackets, packet_length );

	} else {
		/* error ... */
		/* TODO ? */
		is_error = 1;
	}

	//while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
	udelay(100); /* Wait until not busy */

	/*  error or good, tell the card to get rid of this packet */
	SMC_outw( MC_RELEASE, MMU_CMD_REG );

	//while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
	udelay(100); /* Wait until not busy */

	/* restore saved registers */
	SMC_outb( saved_pnr, PN_REG );
	SMC_outw( saved_ptr, PTR_REG );

	if (!is_error) {
		/* Pass the packet up to the protocol layers. */
		RxPacketsLen = packet_length;
		return packet_length;
	} else {
		return 0;
	}

}



/*
 . Function:  smc_hardware_send_packet(struct net_device * )
 . Purpose:
 .	This sends the actual packet to the SMC9xxx chip.
 .
 . Algorithm:
 .	First, see if a saved_skb is available.
 .		( this should NOT be called if there is no 'saved_skb'
 .	Now, find the packet number that the chip allocated
 .	Point the data pointers at it in memory
 .	Set the length word in the chip's memory
 .	Dump the packet to chip memory
 .	Check if a last byte is needed ( odd length packet )
 .		if so, set the control flag right
 .	Tell the card to send it
 .	Enable the transmit interrupt, so I know if it failed
 .	Free the kernel data if I actually sent it.
*/
static int smc_send_packet (volatile void *packet, INT32U packet_length)
{
	INT8U 	packet_no;
	unsigned long ioaddr;
	INT8U	*buf;
	INT32U	length;
	INT32U	numPages;
	INT32U	try = 0;
	INT32U	time_out;
	INT8U	status;
	INT8U	saved_pnr;
	INT16U	saved_ptr;

	
	/* save PTR and PNR registers before manipulation */
	SMC_SELECT_BANK (2);
	saved_pnr = SMC_inb( PN_REG );
	saved_ptr = SMC_inw( PTR_REG );

	OS_DEBUGF(DEV_91C111_DEBUG,("%s:smc_hardware_send_packet\r\n", SMC_DEV_NAME));

	length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;

	/* allocate memory
	 ** The MMU wants the number of pages to be the number of 256 bytes
	 ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
	 **
	 ** The 91C111 ignores the size bits, but the code is left intact
	 ** for backwards and future compatibility.
	 **
	 ** Pkt size for allocating is data length +6 (for additional status
	 ** words, length and ctl!)
	 **
	 ** If odd size then last byte is included in this header.
	 */
	numPages = ((length & 0xfffe) + 6);
	numPages >>= 8;		/* Divide by 256 */

	if (numPages > 7) {

		OS_DEBUGF(DEV_91C111_DEBUG, ("%s: Far too big packet error. \r\n", SMC_DEV_NAME));

		return 0;
	}

	/* now, try to allocate the memory */
	SMC_SELECT_BANK (2);
	SMC_outw (MC_ALLOC | numPages, MMU_CMD_REG);

	/* FIXME: the ALLOC_INT bit never gets set *
	 * so the following will always give a	   *
	 * memory allocation error.		   *
	 * same code works in armboot though	   *
	 * -ro
	 */

again:
	try++;
	time_out = MEMORY_WAIT_TIME;
	do {
		status = SMC_inb (SMC91111_INT_REG);
		if (status & IM_ALLOC_INT) {
			/* acknowledge the interrupt */
			SMC_outb (IM_ALLOC_INT, SMC91111_INT_REG);
			break;
		}
	} while (--time_out);

	if (!time_out) {
	
		OS_DEBUGF(DEV_91C111_DEBUG, ("%s: memory allocation, try %d failed ...\r\n", SMC_DEV_NAME, try));

		if (try < SMC_ALLOC_MAX_TRY)
		{
			if(try < SMC_ALLOC_MAX_TRY-2)
			{
				smc_rcv();
				OS_DEBUGF(DEV_91C111_DEBUG, ("smc_rcv\r\n"));
				goto again;
			}else
			{
				SMC_outw (MC_FREEPKT, MMU_CMD_REG);
				OS_DEBUGF(DEV_91C111_DEBUG, ("smc_outw\r\n"));
				goto again;
			}
		}
		else
		{
	
			OS_DEBUGF(DEV_91C111_DEBUG, ("%s: memory allocation,  failed end\r\n", SMC_DEV_NAME));
			return 0;
		}
		
	}

	OS_DEBUGF(DEV_91C111_DEBUG, ("%s: memory allocation, try %d succeeded ...\r\n", SMC_DEV_NAME, try));

	/* I can send the packet now.. */

	ioaddr = SMC_BASE_ADDRESS;
	ioaddr = ioaddr;

	buf = (INT8U *) packet;

	/* If I get here, I _know_ there is a packet slot waiting for me */
	packet_no = SMC_inb (AR_REG);
	if (packet_no & AR_FAILED) {

		/* or isn't there?  BAD CHIP! */
		OS_DEBUGF(DEV_91C111_DEBUG, ("%s: Memory allocation failed. \r\n", SMC_DEV_NAME));

		return 0;
	}

	/* we have a packet address, so tell the card to use it */
	SMC_outb (packet_no, PN_REG);

	/* do not write new ptr value if Write data fifo not empty */
	while ( saved_ptr & PTR_NOTEMPTY )
		OS_DEBUGF(DEV_91C111_DEBUG, ("Write data fifo not empty!\r\n"));

	/* point to the beginning of the packet */
	SMC_outw (PTR_AUTOINC, PTR_REG);

	OS_DEBUGF(DEV_91C111_DEBUG, ("%s: Trying to xmit packet of length %x\r\n", SMC_DEV_NAME, length));


	OS_DEBUGF(DEV_91C111_DEBUG, ("Transmitting Packet\r\n"));
	//print_packet (buf, length);


	/* send the packet length ( +6 for status, length and ctl byte )
	   and the status word ( set to zeros ) */

	SMC_outw (0, SMC91111_DATA_REG);
	/* send the packet length ( +6 for status words, length, and ctl */
	SMC_outw ((length + 6), SMC91111_DATA_REG);


	/* send the actual data
	   . I _think_ it's faster to send the longs first, and then
	   . mop up by sending the last word.  It depends heavily
	   . on alignment, at least on the 486.	 Maybe it would be
	   . a good idea to check which is optimal?  But that could take
	   . almost as much time as is saved?
	 */

	SMC_outsw (SMC91111_DATA_REG, buf, (length) >> 1);


	/* Send the last byte, if there is one.	  */
	if ((length & 1) == 0) {
		SMC_outw (0, SMC91111_DATA_REG);
	} else {
		SMC_outw (buf[length - 1] | 0x2000, SMC91111_DATA_REG);
	}

	/* and let the chipset deal with it */
	SMC_outw (MC_ENQUEUE, MMU_CMD_REG);

	/* poll for TX INT */
	/* if (poll4int (IM_TX_INT, SMC_TX_TIMEOUT)) { */
	/* poll for TX_EMPTY INT - autorelease enabled */
	if (poll4int(IM_TX_EMPTY_INT, SMC_TX_TIMEOUT)) {
		/* sending failed */

		OS_DEBUGF(DEV_91C111_DEBUG, ("%s: TX timeout, sending failed...\r\n", SMC_DEV_NAME));

		/* release packet */
		/* no need to release, MMU does that now */
		/* SMC_outw (MC_FREEPKT, MMU_CMD_REG); */

		/* wait for MMU getting ready (low) */
		while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
			udelay (10);
		}

		OS_DEBUGF(DEV_91C111_DEBUG, ("MMU ready\r\n"));


		return 0;
	} else {
		/* ack. int */
		SMC_outb (IM_TX_EMPTY_INT, SMC91111_INT_REG);
		/* SMC_outb (IM_TX_INT, SMC91111_INT_REG); */

		OS_DEBUGF(DEV_91C111_DEBUG, ("%s: Sent packet of length %d \r\n", SMC_DEV_NAME, length));


		/* release packet */
		/* no need to release, MMU does that now */
		/* SMC_outw (MC_FREEPKT, MMU_CMD_REG); */

		/* wait for MMU getting ready (low) */
		while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
			udelay (10);
		}

		OS_DEBUGF(DEV_91C111_DEBUG, ("MMU ready\r\n"));


	}

	/* restore previously saved registers */
	SMC_outb( saved_pnr, PN_REG );
	SMC_outw( saved_ptr, PTR_REG );

	return length;
}

INT32U eth_rx (void)
{
	smc_enable();
	return smc_rcv();
}
INT32U eth_send (INT8U *packet, INT32U length)
{
	return smc_send_packet(packet, length);
	
}
void smc_get_macaddr (INT8U *addr)
{
	SMC_SELECT_BANK (1);

	*(INT16U *)(addr+0) = SMC_inw(ADDR0_REG);
	*(INT16U *)(addr+2) = SMC_inw(ADDR1_REG);
	*(INT16U *)(addr+4) = SMC_inw(ADDR2_REG);	
	
}

⌨️ 快捷键说明

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