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

📄 smc91111.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  $Id: smc91111.c,v 1.1.2.1 2005/10/05 19:29:23 joel Exp $ */#include <rtems.h>/* *  This driver currently only supports architectures with the old style *  exception processing.  The following checks try to keep this *  from being compiled on systems which can't support this driver. * *  NOTE: As of 28 September 2005, this has only been tested on the SPARC, *        so that is all it is enabled for. */#if defined(__sparc__)  #define SMC91111_SUPPORTED#endif#if defined(SMC91111_SUPPORTED)#include <bsp.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <rtems/error.h>#include <rtems/rtems_bsdnet.h>#include <sys/param.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/if_ether.h>#define SMC91111_INTERRUPT_EVENT      RTEMS_EVENT_1	/* RTEMS event used by interrupt handler to signal driver tasks. This must not be any of the events used by the network task synchronization. */#define SMC91111_START_TRANSMIT_EVENT RTEMS_EVENT_2	/* RTEMS event used to start transmit/receive daemon. This must not be the same as INTERRUPT_EVENT. */#define SMC91111_TX_WAIT_EVENT        RTEMS_EVENT_3	/* event to send when tx buffers become available *//* Set to perms of:   0 disables all debug output   1 for process debug output   2 for added data IO output: get_reg, put_reg   4 for packet allocation/free output   8 for only startup status, so we can tell we're installed OK   16 dump phy read/write    32 precise register dump   64 dump packets*//*#define DEBUG (-1)*//*#define DEBUG (-1 & ~(16))*/#define DEBUG (0) #include "smc91111config.h"#include <libchip/smc91111.h>struct lan91cxx_priv_data smc91111;int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd);static cyg_uint16 lan91cxx_read_phy(struct lan91cxx_priv_data *cpd,				    cyg_uint8 phyaddr, cyg_uint8 phyreg);static void lan91cxx_write_phy(struct lan91cxx_priv_data *cpd,			       cyg_uint8 phyaddr, cyg_uint8 phyreg,			       cyg_uint16 value);static void lan91cxx_start(struct ifnet *ifp);static void smc91111_start(struct ifnet *ifp);static int smc_probe(struct lan91cxx_priv_data *cpd);static void smc91111_stop(struct lan91cxx_priv_data *cpd);static void smc91111_init(void *arg);static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd);#if 0static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd);static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd);#endif#define min(l,r) ((l) < (r) ? (l) : (r))#define max(l,r) ((l) > (r) ? (l) : (r))/* \ ------------- Interrupt ------------- \ */rtems_isr lan91cxx_interrupt_handler(rtems_vector_number v){	struct lan91cxx_priv_data *cpd = &smc91111;	unsigned short irq, event;	unsigned short oldbase;	unsigned short oldpointer;	INCR_STAT(cpd, interrupts);	DEBUG_FUNCTION();	HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), oldbase);	oldpointer = get_reg(cpd, LAN91CXX_POINTER);	/* Get the (unmasked) requests */	irq = get_reg(cpd, LAN91CXX_INTERRUPT);	event = irq & (irq >> 8) & 0xff;	if (0 == event)		return;	/*put_reg(cpd, LAN91CXX_INTERRUPT, irq ); *//* ack interrupts */	if (event & LAN91CXX_INTERRUPT_ERCV_INT) {		db_printf("Early receive interrupt");	} else if (event & LAN91CXX_INTERRUPT_EPH_INT) {		db_printf("ethernet protocol handler failures");	} else if (event & LAN91CXX_INTERRUPT_RX_OVRN_INT) {		db_printf("receive overrun");	} else if (event & LAN91CXX_INTERRUPT_ALLOC_INT) {		db_printf("allocation interrupt");	} else {		if (event & LAN91CXX_INTERRUPT_TX_SET) {			DEBUG_puts("#tx error\n");			db_printf("#*tx irq\n");			lan91cxx_finish_sent(cpd);			put_reg(cpd, LAN91CXX_INTERRUPT,				(irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT);			/*rtems_event_send (cpd->txDaemonTid, SMC91111_INTERRUPT_EVENT); */			/*put_reg(cpd, LAN91CXX_INTERRUPT, (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT); */			/*rtems_event_send (cpd->txDaemonTid, SMC91111_TX_WAIT_EVENT); */		}		if (event & LAN91CXX_INTERRUPT_RCV_INT) {			db_printf("#*rx irq\n");			rtems_event_send(cpd->rxDaemonTid,					 SMC91111_INTERRUPT_EVENT);		}		if (event &		    ~(LAN91CXX_INTERRUPT_TX_SET | LAN91CXX_INTERRUPT_RCV_INT))			db_printf("Unknown interrupt\n");	}	db_printf("out %s\n", __FUNCTION__);	put_reg(cpd, LAN91CXX_POINTER, oldpointer);	HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), oldbase);}/* \ ------------- Rx receive ------------- \ */ /**//* This function is called as a result of the "readpacket()" call.*//* Its job is to actually fetch data for a packet from the hardware once*//* memory buffers have been allocated for the packet.  Note that the buffers*//* may come in pieces, using a mbuf list.  */static void lan91cxx_recv(struct lan91cxx_priv_data *cpd, struct mbuf *m){	struct ifnet *ifp = &cpd->arpcom.ac_if;	struct ether_header *eh;	short mlen = 0, plen;	char *start;	rxd_t *data = NULL, val, lp;	struct mbuf *n;	lp = 0;	dbg_prefix = "<";	DEBUG_FUNCTION();	INCR_STAT(cpd, rx_deliver);	/* ############ read packet ############ */	put_reg(cpd, LAN91CXX_POINTER,		(LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |		 LAN91CXX_POINTER_AUTO_INCR));	val = get_data(cpd);	/* packet length (minus header/footer) */#ifdef LAN91CXX_32BIT_RX	val = CYG_LE32_TO_CPU(val);	plen = (val >> 16) - 6;#else	val = CYG_LE16_TO_CPU(val);	plen = get_data(cpd);	plen = CYG_LE16_TO_CPU(plen) - 6;#endif	if (LAN91CXX_RX_STATUS_IS_ODD(cpd, val))		plen++;	for (n = m; n; n = n->m_next) {#ifdef LAN91CXX_32BIT_RX		if (mlen == 2) {#if DEBUG & 64			db_printf("Appending to last apacket\n");#endif			val = get_data(cpd);			*((unsigned short *)data) = (val >> 16) & 0xffff;			plen -= 2;			data = (rxd_t *) n->m_data;			start = (char *)data;			mlen = n->m_len;			if ((data) && (mlen > 1)) {				*((unsigned short *)data)++ = (val & 0xffff);				plen -= 2;				mlen -= 2;			}		} else {			data = (rxd_t *) n->m_data;			start = (char *)data;			mlen = n->m_len;		}#else		data = (rxd_t *) n->m_data;		start = (char *)data;		mlen = n->m_len;#endif		db1_printf("<[packet : mlen 0x%x, plen 0x%x]\n", mlen, plen);		if (data) {			while (mlen >= sizeof(*data)) {#ifdef LAN91CXX_32BIT_RX				val = get_data(cpd);				*((unsigned short *)data)++ =				    (val >> 16) & 0xffff;				*((unsigned short *)data)++ = (val & 0xffff);#else				*data++ = get_data(cpd);#endif				mlen -= sizeof(*data);				plen -= sizeof(*data);			}		} else {	/* must actively discard ie. read it from the chip anyway. */			while (mlen >= sizeof(*data)) {				(void)get_data(cpd);				mlen -= sizeof(*data);				plen -= sizeof(*data);			}		}#if DEBUG & 64		lp = 0;		while (((int)start) < ((int)data)) {			unsigned char a = *(start++);			unsigned char b = *(start++);			db64_printf("%02x %02x ", a, b);			lp += 2;			if (lp >= 16) {				db64_printf("\n");				lp = 0;			}		}		db64_printf(" \n");#endif	}	val = get_data(cpd);	/* Read control word (and potential data) unconditionally */#ifdef LAN91CXX_32BIT_RX	if (plen & 2) {		if (data) {			*((unsigned short *)data)++ = (val >> 16) & 0xffff;			val <<= 16;		}	}	if (plen & 1)		*(unsigned char *)data = val >> 24;#else	val = CYG_LE16_TO_CPU(val);	cp = (unsigned char *)data;	CYG_ASSERT(val & LAN91CXX_CONTROLBYTE_RX, "Controlbyte is not for Rx");	CYG_ASSERT((1 == mlen) == (0 != LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)),		   "Controlbyte does not match");	if (data && (1 == mlen) && LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)) {		cval = val & 0x00ff;	/* last byte contains data */		*cp = cval;	}#endif	val = get_reg(cpd, LAN91CXX_FIFO_PORTS);	if (0x8000 & val) {	/* Then the Rx FIFO is empty */		db4_printf		    ("<+Rx packet NOT freed, stat is %x (expected %x)\n",		     val, cpd->rxpacket);	} else {		db4_printf("<+Rx packet freed %x (expected %x)\n",			   0xff & (val >> 8), cpd->rxpacket);	}	CYG_ASSERT((0xff & (val >> 8)) == cpd->rxpacket,		   "Unexpected rx packet");	/* ############ free packet ############ */	/* Free packet */	put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);	dbg_prefix = "";	/* Remove the mac header. This is different from the NetBSD stack. */	eh = mtod(m, struct ether_header *);	m->m_data += sizeof(struct ether_header);	m->m_len -= sizeof(struct ether_header);	m->m_pkthdr.len -= sizeof(struct ether_header);	ether_input(ifp, eh, m);}/* allocate mbuf chain */static struct mbuf *smc91111_allocmbufchain(int totlen, struct ifnet *ifp){	struct mbuf *m, *m0, *newm;	int len;	MGETHDR(m0, M_DONTWAIT, MT_DATA);	if (m0 == 0)		return (0);	m0->m_pkthdr.rcvif = ifp;	m0->m_pkthdr.len = totlen;	len = MHLEN;	m = m0;	/* This loop goes through and allocates mbufs for all the data we will be copying in.  */	while (totlen > 0) {		if (totlen >= MINCLSIZE) {			MCLGET(m, M_DONTWAIT);			if ((m->m_flags & M_EXT) == 0)				goto bad;			len = MCLBYTES;		}		if (m == m0) {			caddr_t newdata = (caddr_t)			    ALIGN(m->m_data +				  sizeof(struct ether_header)) -			    sizeof(struct ether_header);			len -= newdata - m->m_data;			m->m_data = newdata;		}		m->m_len = len = min(totlen, len);		totlen -= len;		if (totlen > 0) {			MGET(newm, M_DONTWAIT, MT_DATA);			if (newm == 0)				goto bad;			len = MLEN;			m = m->m_next = newm;		}	}	return (m0);      bad:	m_freem(m0);	return (0);}static int readpacket(struct lan91cxx_priv_data *cpd){	struct mbuf *m;	unsigned short stat, complen;	struct ifnet *ifp = &cpd->arpcom.ac_if;#ifdef LAN91CXX_32BIT_RX	cyg_uint32 val;#endif	DEBUG_FUNCTION();	/* ############ read packet nr ############ */	stat = get_reg(cpd, LAN91CXX_FIFO_PORTS);	db1_printf("+LAN91CXX_FIFO_PORTS: 0x%04x\n", stat);	if (0x8000 & stat) {		/* Then the Rx FIFO is empty */		db4_printf("!RxEvent with empty fifo\n");		return 0;	}	INCR_STAT(cpd, rx_count);	db4_printf("+Rx packet allocated %x (previous %x)\n",		   0xff & (stat >> 8), cpd->rxpacket);	/* There is an Rx Packet ready */	cpd->rxpacket = 0xff & (stat >> 8);	/* ############ read packet header ############ */	/* Read status and (word) length */	put_reg(cpd, LAN91CXX_POINTER,		(LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |		 LAN91CXX_POINTER_AUTO_INCR | 0x0000));#ifdef LAN91CXX_32BIT_RX	val = get_data(cpd);	val = CYG_LE32_TO_CPU(val);	stat = val & 0xffff;	complen = ((val >> 16) & 0xffff) - 6;	/* minus header/footer words */#else	stat = get_data(cpd);	stat = CYG_LE16_TO_CPU(stat);	complen = get_data(cpd);	complen = CYG_LE16_TO_CPU(len) - 6;	/* minus header/footer words */#endif#ifdef KEEP_STATISTICS	if (stat & LAN91CXX_RX_STATUS_ALIGNERR)		INCR_STAT(cpd, rx_align_errors);	/*if ( stat & LAN91CXX_RX_STATUS_BCAST    ) INCR_STAT(  ); */	if (stat & LAN91CXX_RX_STATUS_BADCRC)		INCR_STAT(cpd, rx_crc_errors);	if (stat & LAN91CXX_RX_STATUS_TOOLONG)		INCR_STAT(cpd, rx_too_long_frames);	if (stat & LAN91CXX_RX_STATUS_TOOSHORT)		INCR_STAT(cpd, rx_short_frames);	/*if ( stat & LAN91CXX_RX_STATUS_MCAST    ) INCR_STAT(  ); */#endif				/* KEEP_STATISTICS */	if ((stat & LAN91CXX_RX_STATUS_BAD) == 0) {		INCR_STAT(cpd, rx_good);		/* Then it's OK */		if (LAN91CXX_RX_STATUS_IS_ODD(cpd, stat))			complen++;#if DEBUG & 1		db_printf("good rx - stat: 0x%04x, len: 0x%04x\n", stat,			  complen);#endif		/* Check for bogusly short packets; can happen in promisc mode: */		/* Asserted against and checked by upper layer driver. */		if (complen > sizeof(struct ether_header)) {			/* then it is acceptable; offer the data to the network stack */			complen = ((complen + 3) & ~3);			m = smc91111_allocmbufchain(complen, ifp);			{				struct mbuf *n = m;				db_printf("mbuf-chain:");				while (n) {					db_printf("[%x:%x]",						  (unsigned int)(n->								 m_data),						  (unsigned int)(n->m_len));					n = n->m_next;				}				db_printf("\n");			}			if (m) {				/* fetch packet data into mbuf chain */				lan91cxx_recv(cpd, m);				return 1;			}		}		/*(sc->funs->eth_drv->recv)(sc, len); */	}	/* Not OK for one reason or another... */	db1_printf("!bad rx: stat: 0x%04x, len: 0x%04x\n", stat, complen);	/* ############ free packet ############ */	/* Free packet */	put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);	return 1;}static void smc91111_rxDaemon(void *arg){	struct lan91cxx_priv_data *cpd = arg;	rtems_event_set events;	DEBUG_FUNCTION();	for (;;) {		rtems_bsdnet_event_receive(INTERRUPT_EVENT,					   RTEMS_WAIT | RTEMS_EVENT_ANY,					   RTEMS_NO_TIMEOUT, &events);		/* read until read fifo is empty */		while (!(get_reg(cpd, LAN91CXX_FIFO_PORTS) & 0x8000)) {			readpacket(cpd);		}	}}/* \ ------------- Tx send ------------- \ */static void sendpacket(struct ifnet *ifp, struct mbuf *m){	struct lan91cxx_priv_data *cpd = ifp->if_softc;	int i, len, plen, tcr;	struct mbuf *n = m;	unsigned short *sdata = NULL;	unsigned short ints, control;	cyg_uint16 packet, status;	dbg_prefix = ">";	DEBUG_FUNCTION();	cpd->txbusy = 1;	/* Worry about the TX engine stopping. */	tcr = get_reg(cpd, LAN91CXX_TCR);	if (0 == (LAN91CXX_TCR_TXENA & tcr)) {		db1_printf("> ENGINE RESTART: tcr %x\n", tcr);		tcr |= LAN91CXX_TCR_TXENA;		put_reg(cpd, LAN91CXX_TCR, tcr);	}	/* ############ packet allocation ############ */	/* Find packet length */	plen = 0;	while (n) {		plen += n->m_len;		n = n->m_next;	}	/* Alloc new TX packet */	do {		put_reg(cpd, LAN91CXX_MMU_COMMAND,			LAN91CXX_MMU_alloc_for_tx | ((plen >> 8) & 0x07));		i = 1024 * 1024;		do {			status = get_reg(cpd, LAN91CXX_INTERRUPT);		} while (0 == (status & LAN91CXX_INTERRUPT_ALLOC_INT)			 && (--i > 0));		if (i)			packet = get_reg(cpd, LAN91CXX_PNR);		else			packet = 0xffff;		db1_printf(">+allocated packet %04x\n", packet);		packet = packet >> 8;		if (packet & 0x80) {			/* Hm.. Isn't this a dead end? */			db1_printf("Allocation failed! Retrying...\n");

⌨️ 快捷键说明

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