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

📄 rtl8019as.c

📁 linux下的RTL8019驱动源码
💻 C
字号:
/*------------------------------------------------------------------------ . RTL8019AS.c . This is a driver for RTL's 8019AS single-chip Ethernet device. . . (C) Copyright 2003 ----------------------------------------------------------------------------*/#include  "44b.h"#include  "lwip_opt.h"#include  "lwip_def.h"#include  "lwip_mem.h"#include  "lwip_pbuf.h"#include  "lwip_sys.h"#include  "lwip_stats.h"#include  "lwip_etharp.h"#include  "Rtl8019.h"#define	RPSTART	0x4c#define	RPSTOP	0x80#define	SPSTART	0x40static unsigned int RBNRY;#define RTL_BASE_ADDRESS 0x6000000struct RTL8019if {    struct eth_addr *ethaddr;    // Add whatever per-interface state that is needed here.}PACK_STRUCT_STRUCT;static char rtl_mac_addr[] = {0x02, 0x80, 0xad, 0x20, 0x31, 0xb8}; const struct eth_addr ethbroadcast = {0xff,0xff,0xff,0xff,0xff,0xff};struct netif *rtl8019if_netif;typedef unsigned char	byte;static byte RTL_inb( unsigned int regxx ){	byte regvalue,*pt;	pt = (byte*)(RTL_BASE_ADDRESS + regxx);	regvalue = *pt;	return(regvalue);}static void RTL_outb(byte regvalue , unsigned int regxx){	byte *pt;	pt = (byte*)(RTL_BASE_ADDRESS + regxx);	*pt = regvalue;}/* select a register bank, 0 to 3  */#define RTL_SELECT_BANK(x)  {\	byte temp;\	temp = RTL_inb(0);\	temp = (temp&0x03b)|(x<<6);\	RTL_outb(temp,0);\}static unsigned char rtl_reset( void );static unsigned char rtl_reset( void ){	//int i;		RTL_outb(0x5a,RstAddr);	//i = 20000;		//old 20000	//while(i--);	OSTimeDly(OS_TICKS_PER_SEC);	RTL_SELECT_BANK(0);	return (RTL_inb(ISR)&0x80);}static void low_level_init(struct netif * netif){	u16_t i;		RTL_SELECT_BANK(3);		RTL_outb(0xcf,CR9346);		//set eem1-0, 11 ,enable write config register	RTL_outb(0x68,CONFIG3);		//clear pwrdn, sleep mode, set led0 as led_col, led1 as led_crs	old 0x68	RTL_outb((RTL_inb(CONFIG1)|0x80),CONFIG1);	RTL_outb(0x3f,CR9346); 		//disable write config register		i = rtl_reset();	RTL_outb(0x21,RCPORT);		// set page 0 and stop 	RTL_outb(RPSTART,Pstart);	// set Pstart 0x4c 	RTL_outb(RPSTOP,Pstop);		// set Pstop 0x80 	RTL_outb(RPSTART,BNRY);		// BNRY-> the last page has been read 		RTL_outb(SPSTART,TPSR);		// transmit page start register, 0x40 	RTL_outb(0xcc,RCR);		// set RCR 0xcc 		RTL_outb(0xe0,TCR);		// set TCR 0xe0 		RTL_outb(0xc8,DCR);		// 8bit DMA 0xc8	RTL_outb(ISR_OVW | ISR_TXE | ISR_PRX, IMR);		// set IMR	RTL_outb(0xff,ISR);			RTL_SELECT_BANK(1);		RTL_outb(RPSTART+1,CURR);	RTL_outb(0x00,MAR0);	RTL_outb(0x41,MAR1);	RTL_outb(0x00,MAR2);	RTL_outb(0x80,MAR3);	RTL_outb(0x00,MAR4);	RTL_outb(0x00,MAR5);	RTL_outb(0x00,MAR6);	RTL_outb(0x00,MAR7);	RTL_outb(0x22,RCPORT);		// set page 0 and start 		RBNRY = RPSTART;		i  = RTL_inb(ID8019L);		//READ RTL8019 ID	i |= RTL_inb(ID8019H)<<8;	RTL_SELECT_BANK(1);	for(i=0; i<6; i++){		RTL_outb(rtl_mac_addr[i],PAR0+i);		netif->hwaddr[i] = rtl_mac_addr[i];	}	/* set MAC hardware address length */	netif->hwaddr_len = 6;	/* maximum transfer unit */	netif->mtu = 1500;	/* broadcast capability */	netif->flags = NETIF_FLAG_BROADCAST;    rINTMSK &= ~(Ethernet_EINT1);                        // 开中断屏蔽位.            rtl8019if_netif = netif;}//static int rtl_send_packet(volatile void *packet, int packet_length)err_t low_level_send(struct netif *rtl8019if,struct pbuf *p){	static u16_t sFlag = 0;	u16_t i;	u8_t send_page;	u8_t isr;	u8_t *data;	u16_t padLength,packetLength;	struct pbuf *q;	    padLength = 0;                         // Set up to transfer the packet contents to the NIC RAM.    packetLength = p->tot_len;    if ((p->tot_len) < 60) {               // packetLength muse >=64 (see 802.3)        padLength = 60 - (p->tot_len);        packetLength = 60;    }			while(RTL_inb(RCPORT)&4);	RTL_SELECT_BANK(2);	isr = RTL_inb(IMR);	isr &= ~ISR_PRX;				// close receive interrupt	RTL_SELECT_BANK(0);	RTL_outb(isr,IMR);		#if ETH_PAD_SIZE  pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */#endif		for(q = p; q != NULL; q = q->next){		send_page  = SPSTART;		send_page += (sFlag&1)?6:0;		sFlag++;															RTL_SELECT_BANK(0);				RTL_outb(0x22,RCPORT);					RTL_outb(0,RSAR0);		RTL_outb(send_page,RSAR1);		RTL_outb(packetLength&0xff,RBCR0);			RTL_outb(((packetLength>>8)&0xff),RBCR1);					RTL_outb(0x12,RCPORT);					data = q->payload;		for(i=0; i<q->len; i++)		{								RTL_outb(*data++,RWPORT);		// tarns to ram		}					RTL_outb(send_page,TPSR);		RTL_outb(packetLength&0xff,TBCR0);			RTL_outb(((packetLength>>8)&0xff),TBCR1);						RTL_outb(0x1e,RCPORT);				// begin to send						}	RTL_SELECT_BANK(2);	isr = RTL_inb(IMR);	isr |= ISR_PRX;				// reopen receive interrupt	RTL_SELECT_BANK(0);	RTL_outb(isr,IMR);#if ETH_PAD_SIZE  pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */#endif	//pbuf_free(p);	#ifdef LINK_STATS    lwip_stats.link.xmit++;#endif    return (ERR_OK);}//static int rtl_rcv( void )static struct pbuf * low_level_receive(struct RTL8019if *rtl8019if){	u8_t RxPageBeg, RxPageEnd;	u8_t RxNextPage;	u8_t RxStatus;	u8_t *addr;	u16_t i, RxLength;	struct pbuf * p, *q;				RTL_SELECT_BANK(1);	RxPageEnd = RTL_inb(CURR);	RxPageBeg = RBNRY+1;	if(RxPageBeg>=RPSTOP)		RxPageBeg = RPSTART;					RTL_SELECT_BANK(0);	RTL_outb(0x22,RCPORT);			RTL_outb(0,RSAR0);	RTL_outb(RxPageBeg,RSAR1);	RTL_outb(4,RBCR0);	RTL_outb(0,RBCR1);	RTL_outb(0x0a,RCPORT);	RxStatus   = RTL_inb(RWPORT);	RxNextPage = RTL_inb(RWPORT);		RxLength   = RTL_inb(RWPORT);	RxLength  |= RTL_inb(RWPORT)<<8;#if ETH_PAD_SIZE  RxLength += ETH_PAD_SIZE;						/* allow room for Ethernet padding */#endif		if(RxLength>ETH_FRAME_LEN){		if(RxPageEnd==RPSTART)			RBNRY = RPSTOP-1;		else			RBNRY = RxPageEnd-1;								RTL_outb(RBNRY,BNRY);		 			return 0;			}			if ( !(RxStatus & RS_ERRORS ) ){		// We allocate a pbuf chain of pbufs from the pool.		p = pbuf_alloc(PBUF_LINK, RxLength, PBUF_POOL);				if(p != NULL){			#if ETH_PAD_SIZE    pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */#endif						for(q = p; q != NULL; q = q->next){				RTL_outb(4,RSAR0);				RTL_outb(RxPageBeg,RSAR1);				RTL_outb(q->len,RBCR0);				RTL_outb((q->len)>>8,RBCR1);					RTL_outb(0x0a,RCPORT);				addr = q->payload;				for(i=0;i<=(q->len);i++){								if(i!=0){						if(!(i&0xff)){							RTL_outb(RxPageBeg,BNRY);											RxPageBeg++;							if(RxPageBeg>=RPSTOP)								RxPageBeg = RPSTART;											}						}							*(addr++) = RTL_inb(RWPORT);				}				RBNRY = RxPageBeg;				RTL_outb(RBNRY,BNRY);				}			#if ETH_PAD_SIZE    pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */#endif			#ifdef LINK_STATS        lwip_stats.link.recv++;#endif					} else {#ifdef LINK_STATS        lwip_stats.link.memerr++;        lwip_stats.link.drop++;#endif		if(RxPageEnd==RPSTART)			RBNRY = RPSTOP-1;		else			RBNRY = RxPageEnd-1;								RTL_outb(RBNRY,BNRY);		 			}			} else {		if(RxPageEnd==RPSTART)			RBNRY = RPSTOP-1;		else			RBNRY = RxPageEnd-1;								RTL_outb(RBNRY,BNRY);		 		}		return (p);	}/********************************************************************* 描述: RTL8019AS 中断.********************************************************************/void __irq Exint1_ISR (void){	u8_t  isr,curr;    OSIntEnter();    rI_ISPC = Ethernet_EINT1;	RTL_SELECT_BANK(0);    isr = RTL_inb(ISR);                                // 读取中断悬挂位.    if (isr & ISR_OVW) {                                // 溢出.        RTL_SELECT_BANK(1);        curr = RTL_inb(CURR);        RTL_SELECT_BANK(0);        RTL_outb(curr, BNRY);        RTL_outb(ISR_OVW,ISR);    }    if (isr & ISR_TXE) {    	RTL_SELECT_BANK(0);        RTL_outb(ISR_TXE,ISR);		                    // clear interrupt    }/*        if( isr & ISR_PTX) {                                // Transfer complelte, do nothing here        RTL_outb(ISR_PTX, ISR);    }    if( isr & ISR_RST) {        RTL_outb(ISR_RST, ISR);    }    if( isr & ISR_RDC) {        RTL_outb(ISR_RDC, ISR);    }    if( isr & ISR_CNT) {        RTL_outb(ISR_CNT, ISR);    }    // Rx error , reset BNRY pointer to CURR (use SEND PACKET mode)    if (isr & ISR_RXE) {        RTL_outb(ISR_RXE,ISR);		                    // clear interrupt        RTL_SELECT_BANK(1);        curr = RTL_inb(CURR);        RTL_SELECT_BANK(0);        RTL_outb(curr, BNRY);    }*/    //got packet with no errors    if (isr & ISR_PRX) {		ne2k_recv_packet(rtl8019if_netif);		RTL_SELECT_BANK(0);    	RTL_outb(ISR_PRX, ISR);    }    OSIntExit();}/********************************************************************* Send a packet to the RTK8019as from a series of pbuf buffers.********************************************************************/err_t ne2k_send_packet(struct netif *netif, struct pbuf *p,struct ip_addr *ipaddr){	struct RTL8019if *rtl8019if;	struct pbuf *q;	struct eth_hdr *ethhdr;	struct eth_addr *dest, mcastaddr;	struct ip_addr *queryaddr;	err_t  err;	u8_t   i;    rtl8019if = netif->state;    if(pbuf_header(p, sizeof(struct eth_hdr)) != 0) {                       // Make room for Ethernet header.         q = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);        // The pbuf_header() call shouldn't fail, but we allocate an extra pbuf just in case.        if(q == NULL) {            return (ERR_MEM);        }        pbuf_chain(q, p);        p = q;    }        /* Construct Ethernet header. Start with looking up deciding which           MAC address to use as a destination address. Broadcasts and           multicasts are special, all other addresses are looked up in the           ARP table. */    queryaddr = ipaddr;    i = ip_addr_isbroadcast(ipaddr, netif);    if(ip_addr_isany(ipaddr) || (i != 0)) {        dest = (struct eth_addr *)&ethbroadcast;    } else if (ip_addr_ismulticast(ipaddr)) {        mcastaddr.addr[0] = 0x01;                       // Hash IP multicast address to MAC address.        mcastaddr.addr[1] = 0x0;        mcastaddr.addr[2] = 0x5e;        mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;        mcastaddr.addr[4] = ip4_addr3(ipaddr);        mcastaddr.addr[5] = ip4_addr4(ipaddr);        dest = &mcastaddr;    } else {        if(ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {            queryaddr = ipaddr;                         // Use destination IP address if the destination is on the same subnet as we are.         } else {            queryaddr = &(netif->gw);                   // Otherwise we use the default router as the address to send the Ethernet frame to.        }        dest = etharp_arp_lookup(queryaddr);    }    if(dest == NULL) {                                  // If the arp_lookup() didn't find an address, we send out an ARP query for the IP address.        err= etharp_query(netif, queryaddr, p);        if(err != ERR_OK) {            pbuf_free(p);        }        return err;    }    ethhdr = p->payload;    for(i = 0; i < 6; i++) {        ethhdr->dest.addr[i] = dest->addr[i];        ethhdr->src.addr[i]  = rtl8019if->ethaddr->addr[i];    }    ethhdr->type = htons(ETHTYPE_IP);    return low_level_send(rtl8019if_netif, p);}/********************************************************************* Read a packet, clearing overflows. ********************************************************************/void ne2k_recv_packet(struct netif *netif){	struct RTL8019if *rtl8019if;	struct eth_hdr *ethhdr;	struct pbuf *p;    rtl8019if = netif->state;    p = low_level_receive(rtl8019if);    if(p == NULL) {        return;    }#ifdef LINK_STATS    lwip_stats.link.recv++;#endif    ethhdr = p->payload;    switch(htons(ethhdr->type)) {        case ETHTYPE_IP:                                // 接收到 IP 包.		    /* update ARP table */		    etharp_ip_input(netif, p);		    /* skip Ethernet header */		    pbuf_header(p, -sizeof(struct eth_hdr));		    /* pass to network layer */		    netif->input(p, netif);		    break;        case ETHTYPE_ARP:                               // 接收到 ARP 包.            etharp_arp_input(netif, rtl8019if->ethaddr, p);            break;        default:            pbuf_free(p);            p = NULL;            break;    }}/********************************************************************* eth arp timer.********************************************************************/static void etharp_timer(void *arg){    etharp_tmr();    sys_timeout(ARP_TMR_INTERVAL, etharp_timer, NULL);}/* * ne2k_init(): * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * */err_tne2k_init(struct netif *netif){	struct RTL8019if *rtl8019if;    	rtl8019if = mem_malloc(sizeof(struct RTL8019if));  	if (rtl8019if == NULL)	{		LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));		return ERR_MEM;	}  	netif->state = rtl8019if;	netif->name[0] = 'e';	netif->name[1] = 't';	netif->output = ne2k_send_packet;	netif->linkoutput = low_level_send;  	rtl8019if->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);  	low_level_init(netif);	etharp_init();	sys_timeout(ARP_TMR_INTERVAL, etharp_timer, NULL);	return (ERR_OK);}

⌨️ 快捷键说明

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