xref: /minix3/minix/drivers/net/dpeth/3c501.c (revision 91c4db251e4647e55243c74194190c0fe0202d37)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc **  File:	3c501.c		Jan. 14, 1997
3433d6423SLionel Sambuc **
4433d6423SLionel Sambuc **  Author:	Giovanni Falzoni <gfalzoni@inwind.it>
5433d6423SLionel Sambuc **
6433d6423SLionel Sambuc **  This file contains specific implementation of the ethernet
7433d6423SLionel Sambuc **  device driver for 3Com Etherlink (3c501) boards.  This is a
8433d6423SLionel Sambuc **  very old board and its performances are very poor for today
9433d6423SLionel Sambuc **  network environments.
10433d6423SLionel Sambuc */
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc #include <minix/drivers.h>
13*91c4db25SDavid van Moolenbroek #include <minix/netdriver.h>
14433d6423SLionel Sambuc #include <net/gen/ether.h>
15433d6423SLionel Sambuc #include <net/gen/eth_io.h>
16433d6423SLionel Sambuc #include "dp.h"
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc #if (ENABLE_3C501 == 1)
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc #include "3c501.h"
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,};
23433d6423SLionel Sambuc static buff_t *TxBuff = NULL;
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc /*
26*91c4db25SDavid van Moolenbroek **  Name:	el1_getstats
27433d6423SLionel Sambuc **  Function:	Reads statistics counters from board.
28433d6423SLionel Sambuc **/
29433d6423SLionel Sambuc static void el1_getstats(dpeth_t * dep)
30433d6423SLionel Sambuc {
31433d6423SLionel Sambuc 
32*91c4db25SDavid van Moolenbroek   /* Nothing to do */
33433d6423SLionel Sambuc }
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc /*
36*91c4db25SDavid van Moolenbroek **  Name:	el1_reset
37433d6423SLionel Sambuc **  Function:	Reset function specific for Etherlink hardware.
38433d6423SLionel Sambuc */
39433d6423SLionel Sambuc static void el1_reset(dpeth_t * dep)
40433d6423SLionel Sambuc {
41433d6423SLionel Sambuc   int ix;
42433d6423SLionel Sambuc 
43433d6423SLionel Sambuc   for (ix = 0; ix < 8; ix += 1)	/* Resets the board */
44433d6423SLionel Sambuc 	outb_el1(dep, EL1_CSR, ECSR_RESET);
45433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc   /* Set Ethernet Address on controller */
48433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_LOOP);	/* Loopback mode */
49433d6423SLionel Sambuc   for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1)
50433d6423SLionel Sambuc 	outb_el1(dep, ix, StationAddress[ix]);
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc   /* Enable DMA/Interrupt, gain control of Buffer */
53433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
54433d6423SLionel Sambuc   /* Clear RX packet area */
55433d6423SLionel Sambuc   outw_el1(dep, EL1_RECVPTR, 0);
56433d6423SLionel Sambuc   /* Enable transmit/receive configuration and flush pending interrupts */
57433d6423SLionel Sambuc   outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER);
58433d6423SLionel Sambuc   outb_el1(dep, EL1_RECV, dep->de_recv_mode);
59433d6423SLionel Sambuc   inb_el1(dep, EL1_RECV);
60433d6423SLionel Sambuc   inb_el1(dep, EL1_XMIT);
61433d6423SLionel Sambuc   dep->de_flags &= NOT(DEF_XMIT_BUSY);
62433d6423SLionel Sambuc }
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc /*
65*91c4db25SDavid van Moolenbroek **  Name:	el1_dumpstats
66433d6423SLionel Sambuc **  Function:	Dumps counter on screen (support for console display).
67433d6423SLionel Sambuc */
68433d6423SLionel Sambuc static void el1_dumpstats(dpeth_t * UNUSED(dep))
69433d6423SLionel Sambuc {
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc }
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc /*
74*91c4db25SDavid van Moolenbroek **  Name:	el1_mode_init
75433d6423SLionel Sambuc **  Function:	Initializes receicer mode
76433d6423SLionel Sambuc */
77433d6423SLionel Sambuc static void el1_mode_init(dpeth_t * dep)
78433d6423SLionel Sambuc {
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc   if (dep->de_flags & DEF_BROAD) {
81433d6423SLionel Sambuc 	dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK;
82433d6423SLionel Sambuc 
83433d6423SLionel Sambuc   } else if (dep->de_flags & DEF_PROMISC) {
84433d6423SLionel Sambuc 	dep->de_recv_mode = ERSR_ALL | ERSR_RMASK;
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc   } else if (dep->de_flags & DEF_MULTI) {
87433d6423SLionel Sambuc 	dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK;
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc   } else {
90433d6423SLionel Sambuc 	dep->de_recv_mode = ERSR_NONE | ERSR_RMASK;
91433d6423SLionel Sambuc   }
92433d6423SLionel Sambuc   outb_el1(dep, EL1_RECV, dep->de_recv_mode);
93433d6423SLionel Sambuc   inb_el1(dep, EL1_RECV);
94433d6423SLionel Sambuc }
95433d6423SLionel Sambuc 
96433d6423SLionel Sambuc /*
97*91c4db25SDavid van Moolenbroek **  Name:	el1_recv
98433d6423SLionel Sambuc **  Function:	Receive function.  Called from interrupt handler to
99433d6423SLionel Sambuc **  		unload recv. buffer or from main (packet to client)
100433d6423SLionel Sambuc */
101*91c4db25SDavid van Moolenbroek static ssize_t el1_recv(dpeth_t *dep, struct netdriver_data *data, size_t max)
102433d6423SLionel Sambuc {
103433d6423SLionel Sambuc   buff_t *rxptr;
104*91c4db25SDavid van Moolenbroek   size_t size;
105433d6423SLionel Sambuc 
106*91c4db25SDavid van Moolenbroek   if ((rxptr = dep->de_recvq_head) == NULL)
107*91c4db25SDavid van Moolenbroek 	return SUSPEND;
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc   /* Remove buffer from queue and free buffer */
110433d6423SLionel Sambuc   if (dep->de_recvq_tail == dep->de_recvq_head)
111433d6423SLionel Sambuc 	dep->de_recvq_head = dep->de_recvq_tail = NULL;
112433d6423SLionel Sambuc   else
113433d6423SLionel Sambuc 	dep->de_recvq_head = rxptr->next;
114433d6423SLionel Sambuc 
115433d6423SLionel Sambuc   /* Copy buffer to user area */
116*91c4db25SDavid van Moolenbroek   size = MIN(rxptr->size, max);
117433d6423SLionel Sambuc 
118*91c4db25SDavid van Moolenbroek   netdriver_copyout(data, 0, rxptr->buffer, size);
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc   /* Return buffer to the idle pool */
121433d6423SLionel Sambuc   free_buff(dep, rxptr);
122*91c4db25SDavid van Moolenbroek 
123*91c4db25SDavid van Moolenbroek   return size;
124433d6423SLionel Sambuc }
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc /*
127*91c4db25SDavid van Moolenbroek **  Name:	el1_send
128*91c4db25SDavid van Moolenbroek **  Function:	Send function.
129433d6423SLionel Sambuc */
130*91c4db25SDavid van Moolenbroek static int el1_send(dpeth_t *dep, struct netdriver_data *data, size_t size)
131433d6423SLionel Sambuc {
132433d6423SLionel Sambuc   buff_t *txbuff;
133433d6423SLionel Sambuc   clock_t now;
134433d6423SLionel Sambuc 
135*91c4db25SDavid van Moolenbroek   if (dep->de_flags & DEF_XMIT_BUSY) {
136433d6423SLionel Sambuc 	getticks(&now);
137433d6423SLionel Sambuc 	if ((now - dep->de_xmit_start) > 4) {
138433d6423SLionel Sambuc 		/* Transmitter timed out */
139433d6423SLionel Sambuc 		DEBUG(printf("3c501: transmitter timed out ... \n"));
140433d6423SLionel Sambuc 		dep->de_stat.ets_sendErr += 1;
141433d6423SLionel Sambuc 		dep->de_flags &= NOT(DEF_XMIT_BUSY);
142*91c4db25SDavid van Moolenbroek 		/* Try sending anyway. */
143*91c4db25SDavid van Moolenbroek 	} else
144*91c4db25SDavid van Moolenbroek 		return SUSPEND;
145433d6423SLionel Sambuc   }
146433d6423SLionel Sambuc 
147*91c4db25SDavid van Moolenbroek   /* Since we may have to retransmit, we need a local copy. */
148*91c4db25SDavid van Moolenbroek   if ((txbuff = alloc_buff(dep, size + sizeof(buff_t))) == NULL)
149*91c4db25SDavid van Moolenbroek 	panic("out of memory");
150*91c4db25SDavid van Moolenbroek 
151*91c4db25SDavid van Moolenbroek   /* Fill transmit buffer from user area */
152*91c4db25SDavid van Moolenbroek   txbuff->next = NULL;
153*91c4db25SDavid van Moolenbroek   txbuff->size = size;
154*91c4db25SDavid van Moolenbroek 
155*91c4db25SDavid van Moolenbroek   netdriver_copyin(data, 0, txbuff->buffer, size);
156*91c4db25SDavid van Moolenbroek 
157433d6423SLionel Sambuc   /* Save for retransmission */
158433d6423SLionel Sambuc   TxBuff = txbuff;
159*91c4db25SDavid van Moolenbroek   dep->de_flags |= DEF_XMIT_BUSY;
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc   /* Setup board for packet loading */
162433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
163433d6423SLionel Sambuc   inb_el1(dep, EL1_RECV);	/* Clears any spurious interrupt */
164433d6423SLionel Sambuc   inb_el1(dep, EL1_XMIT);
165433d6423SLionel Sambuc   outw_el1(dep, EL1_RECVPTR, 0);	/* Clears RX packet area */
166433d6423SLionel Sambuc 
167433d6423SLionel Sambuc   /* Loads packet */
168*91c4db25SDavid van Moolenbroek   outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size));
169*91c4db25SDavid van Moolenbroek   outsb(dep->de_data_port, txbuff->buffer, size);
170433d6423SLionel Sambuc   /* Starts transmitter */
171*91c4db25SDavid van Moolenbroek   outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size));
172433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);	/* There it goes... */
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc   getticks(&dep->de_xmit_start);
175*91c4db25SDavid van Moolenbroek 
176*91c4db25SDavid van Moolenbroek   return OK;
177433d6423SLionel Sambuc }
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc /*
180*91c4db25SDavid van Moolenbroek **  Name:	el1_stop
181433d6423SLionel Sambuc **  Function:	Stops board and disable interrupts.
182433d6423SLionel Sambuc */
183433d6423SLionel Sambuc static void el1_stop(dpeth_t * dep)
184433d6423SLionel Sambuc {
185433d6423SLionel Sambuc   int ix;
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc   DEBUG(printf("%s: stopping Etherlink ....\n", dep->de_name));
188433d6423SLionel Sambuc   for (ix = 0; ix < 8; ix += 1)	/* Reset board */
189433d6423SLionel Sambuc 	outb_el1(dep, EL1_CSR, ECSR_RESET);
190433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_SYS);
191433d6423SLionel Sambuc   sys_irqdisable(&dep->de_hook);	/* Disable interrupt */
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc /*
195*91c4db25SDavid van Moolenbroek **  Name:	el1_interrupt
196433d6423SLionel Sambuc **  Function:	Interrupt handler.  Acknwledges transmit interrupts
197433d6423SLionel Sambuc **  		or unloads receive buffer to memory queue.
198433d6423SLionel Sambuc */
199433d6423SLionel Sambuc static void el1_interrupt(dpeth_t * dep)
200433d6423SLionel Sambuc {
201433d6423SLionel Sambuc   u16_t csr, isr;
202433d6423SLionel Sambuc   int pktsize;
203433d6423SLionel Sambuc   buff_t *rxptr;
204433d6423SLionel Sambuc 
205433d6423SLionel Sambuc   csr = inb_el1(dep, EL1_CSR);
206433d6423SLionel Sambuc   if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) {
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc 	/* Got a transmit interrupt */
209433d6423SLionel Sambuc 	isr = inb_el1(dep, EL1_XMIT);
210433d6423SLionel Sambuc 	if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) {
211433d6423SLionel Sambuc 	DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr));
212433d6423SLionel Sambuc 		if (isr & EXSR_JAM) {
213433d6423SLionel Sambuc 			/* Sending, packet got a collision */
214433d6423SLionel Sambuc 			dep->de_stat.ets_collision += 1;
215433d6423SLionel Sambuc 			/* Put pointer back to beginning of packet */
216433d6423SLionel Sambuc 			outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
217433d6423SLionel Sambuc 			outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size));
218433d6423SLionel Sambuc 			/* And retrigger transmission */
219433d6423SLionel Sambuc 			outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);
220433d6423SLionel Sambuc 			return;
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 		} else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) {
223433d6423SLionel Sambuc 			dep->de_stat.ets_sendErr += 1;
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 		} else if (isr & EXSR_UNDER) {
226433d6423SLionel Sambuc 			dep->de_stat.ets_fifoUnder += 1;
227433d6423SLionel Sambuc 		}
228433d6423SLionel Sambuc 		DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr));
229433d6423SLionel Sambuc 		el1_reset(dep);
230433d6423SLionel Sambuc 	} else {
231433d6423SLionel Sambuc 		/** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/
232433d6423SLionel Sambuc 		/* Packet transmitted successfully */
233433d6423SLionel Sambuc 		dep->de_stat.ets_packetT += 1;
234433d6423SLionel Sambuc 		dep->bytes_Tx += (long) (TxBuff->size);
235433d6423SLionel Sambuc 		free_buff(dep, TxBuff);
236433d6423SLionel Sambuc 		dep->de_flags &= NOT(DEF_XMIT_BUSY);
237*91c4db25SDavid van Moolenbroek 		netdriver_send();
238*91c4db25SDavid van Moolenbroek 		if (dep->de_flags & DEF_XMIT_BUSY)
239433d6423SLionel Sambuc 			return;
240433d6423SLionel Sambuc 	}
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc   } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) {
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc 	/* Got a receive interrupt */
245433d6423SLionel Sambuc 	isr = inb_el1(dep, EL1_RECV);
246433d6423SLionel Sambuc 	pktsize = inw_el1(dep, EL1_RECVPTR);
247433d6423SLionel Sambuc 	if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) {
248433d6423SLionel Sambuc 	DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
249433d6423SLionel Sambuc 		dep->de_stat.ets_recvErr += 1;
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc 	} else if (pktsize < ETH_MIN_PACK_SIZE || pktsize > ETH_MAX_PACK_SIZE) {
252433d6423SLionel Sambuc 	DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
253433d6423SLionel Sambuc 		dep->de_stat.ets_recvErr += 1;
254433d6423SLionel Sambuc 
255433d6423SLionel Sambuc 	} else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) {
256433d6423SLionel Sambuc 		/* Memory not available. Drop packet */
257433d6423SLionel Sambuc 		dep->de_stat.ets_fifoOver += 1;
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc 	} else if (isr & (ERSR_GOOD | ERSR_ANY)) {
260433d6423SLionel Sambuc 		/* Got a good packet. Read it from buffer */
261433d6423SLionel Sambuc 		outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
262433d6423SLionel Sambuc 		outw_el1(dep, EL1_XMITPTR, 0);
263*91c4db25SDavid van Moolenbroek 		insb(dep->de_data_port, rxptr->buffer, pktsize);
264433d6423SLionel Sambuc 		rxptr->next = NULL;
265433d6423SLionel Sambuc 		rxptr->size = pktsize;
266433d6423SLionel Sambuc 		dep->de_stat.ets_packetR += 1;
267433d6423SLionel Sambuc 		dep->bytes_Rx += (long) pktsize;
268*91c4db25SDavid van Moolenbroek 		/* Queue packet to receive queue */
269433d6423SLionel Sambuc 		if (dep->de_recvq_head == NULL)
270433d6423SLionel Sambuc 			dep->de_recvq_head = rxptr;
271433d6423SLionel Sambuc 		else
272433d6423SLionel Sambuc 			dep->de_recvq_tail->next = rxptr;
273433d6423SLionel Sambuc 		dep->de_recvq_tail = rxptr;
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc 		/* Reply to pending Receive requests, if any */
276*91c4db25SDavid van Moolenbroek 		netdriver_recv();
277433d6423SLionel Sambuc 	}
278433d6423SLionel Sambuc   } else {			/* Nasty condition, should never happen */
279433d6423SLionel Sambuc 	DEBUG(
280433d6423SLionel Sambuc 	      printf("3c501: got interrupt with status 0x%02X\n"
281433d6423SLionel Sambuc 		     "       de_flags=0x%04X  XSR=0x%02X RSR=0x%02X \n"
282433d6423SLionel Sambuc 		     "       xmit buffer = 0x%4X recv buffer = 0x%4X\n",
283433d6423SLionel Sambuc 			csr, dep->de_flags,
284433d6423SLionel Sambuc 			inb_el1(dep, EL1_RECV),
285433d6423SLionel Sambuc 			inb_el1(dep, EL1_XMIT),
286433d6423SLionel Sambuc 			inw_el1(dep, EL1_XMITPTR),
287433d6423SLionel Sambuc 			inw_el1(dep, EL1_RECVPTR))
288433d6423SLionel Sambuc 		);
289433d6423SLionel Sambuc 	el1_reset(dep);
290433d6423SLionel Sambuc   }
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc   /* Move into receive mode */
293433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
294433d6423SLionel Sambuc   outw_el1(dep, EL1_RECVPTR, 0);
295433d6423SLionel Sambuc   /* Be sure that interrupts are cleared */
296433d6423SLionel Sambuc   inb_el1(dep, EL1_RECV);
297433d6423SLionel Sambuc   inb_el1(dep, EL1_XMIT);
298433d6423SLionel Sambuc }
299433d6423SLionel Sambuc 
300433d6423SLionel Sambuc /*
301*91c4db25SDavid van Moolenbroek **  Name:	el1_init
302433d6423SLionel Sambuc **  Function:	Initalizes board hardware and driver data structures.
303433d6423SLionel Sambuc */
304433d6423SLionel Sambuc static void el1_init(dpeth_t * dep)
305433d6423SLionel Sambuc {
306433d6423SLionel Sambuc   int ix;
307433d6423SLionel Sambuc 
308433d6423SLionel Sambuc   dep->de_irq &= NOT(DEI_DEFAULT);	/* Strip the default flag. */
309433d6423SLionel Sambuc   dep->de_offset_page = 0;
310433d6423SLionel Sambuc   dep->de_data_port = dep->de_base_port + EL1_DATAPORT;
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc   el1_reset(dep);		/* Reset and initialize board */
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc   /* Start receiver (default mode) */
315433d6423SLionel Sambuc   outw_el1(dep, EL1_RECVPTR, 0);
316433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc   /* Initializes buffer pool */
319433d6423SLionel Sambuc   init_buff(dep, NULL);
320433d6423SLionel Sambuc   el1_mode_init(dep);
321433d6423SLionel Sambuc 
322433d6423SLionel Sambuc   printf("%s: Etherlink (%s) at %X:%d - ",
323433d6423SLionel Sambuc          dep->de_name, "3c501", dep->de_base_port, dep->de_irq);
324433d6423SLionel Sambuc   for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
325433d6423SLionel Sambuc 	printf("%02X%c", (dep->de_address.ea_addr[ix] = StationAddress[ix]),
326433d6423SLionel Sambuc 	       ix < SA_ADDR_LEN - 1 ? ':' : '\n');
327433d6423SLionel Sambuc 
328433d6423SLionel Sambuc   /* Device specific functions */
329433d6423SLionel Sambuc   dep->de_recvf = el1_recv;
330433d6423SLionel Sambuc   dep->de_sendf = el1_send;
331433d6423SLionel Sambuc   dep->de_flagsf = el1_mode_init;
332433d6423SLionel Sambuc   dep->de_resetf = el1_reset;
333433d6423SLionel Sambuc   dep->de_getstatsf = el1_getstats;
334433d6423SLionel Sambuc   dep->de_dumpstatsf = el1_dumpstats;
335433d6423SLionel Sambuc   dep->de_interruptf = el1_interrupt;
336433d6423SLionel Sambuc }
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc /*
339*91c4db25SDavid van Moolenbroek **  Name:	el1_probe
340433d6423SLionel Sambuc **  Function:	Checks for presence of the board.
341433d6423SLionel Sambuc */
342433d6423SLionel Sambuc int el1_probe(dpeth_t * dep)
343433d6423SLionel Sambuc {
344433d6423SLionel Sambuc   int ix;
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc   for (ix = 0; ix < 8; ix += 1)	/* Reset the board */
347433d6423SLionel Sambuc 	outb_el1(dep, EL1_CSR, ECSR_RESET);
348433d6423SLionel Sambuc   outb_el1(dep, EL1_CSR, ECSR_SYS);	/* Leaves buffer to system */
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc   /* Check station address */
351433d6423SLionel Sambuc   for (ix = 0; ix < SA_ADDR_LEN; ix += 1) {
352433d6423SLionel Sambuc 	outw_el1(dep, EL1_XMITPTR, ix);
353433d6423SLionel Sambuc 	StationAddress[ix] = inb_el1(dep, EL1_SAPROM);
354433d6423SLionel Sambuc   }
355433d6423SLionel Sambuc   if (StationAddress[0] != 0x02 ||	/* Etherlink Station address  */
356433d6423SLionel Sambuc       StationAddress[1] != 0x60 ||	/* MUST be 02:60:8c:xx:xx:xx  */
357433d6423SLionel Sambuc       StationAddress[2] != 0x8C)
358433d6423SLionel Sambuc 	return FALSE;		/* No Etherlink board at this address */
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc   dep->de_ramsize = 0;		/* RAM size is meaningless */
361433d6423SLionel Sambuc   dep->de_linmem = 0L;		/* Access is via I/O port  */
362433d6423SLionel Sambuc 
363433d6423SLionel Sambuc   /* Device specific functions */
364433d6423SLionel Sambuc   dep->de_initf = el1_init;
365433d6423SLionel Sambuc   dep->de_stopf = el1_stop;
366433d6423SLionel Sambuc 
367433d6423SLionel Sambuc   return TRUE;			/* Etherlink board found */
368433d6423SLionel Sambuc }
369433d6423SLionel Sambuc 
370433d6423SLionel Sambuc #endif				/* ENABLE_3C501 */
371433d6423SLionel Sambuc 
372433d6423SLionel Sambuc /** 3c501.c **/
373