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>
1391c4db25SDavid van Moolenbroek #include <minix/netdriver.h>
14433d6423SLionel Sambuc #include "dp.h"
15433d6423SLionel Sambuc
16433d6423SLionel Sambuc #if (ENABLE_3C501 == 1)
17433d6423SLionel Sambuc
18433d6423SLionel Sambuc #include "3c501.h"
19433d6423SLionel Sambuc
20433d6423SLionel Sambuc static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,};
21433d6423SLionel Sambuc static buff_t *TxBuff = NULL;
22433d6423SLionel Sambuc
23433d6423SLionel Sambuc /*
2491c4db25SDavid van Moolenbroek ** Name: el1_getstats
25433d6423SLionel Sambuc ** Function: Reads statistics counters from board.
26433d6423SLionel Sambuc **/
el1_getstats(dpeth_t * dep)27433d6423SLionel Sambuc static void el1_getstats(dpeth_t * dep)
28433d6423SLionel Sambuc {
29433d6423SLionel Sambuc
3091c4db25SDavid van Moolenbroek /* Nothing to do */
31433d6423SLionel Sambuc }
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc /*
3491c4db25SDavid van Moolenbroek ** Name: el1_reset
35433d6423SLionel Sambuc ** Function: Reset function specific for Etherlink hardware.
36433d6423SLionel Sambuc */
el1_reset(dpeth_t * dep)37433d6423SLionel Sambuc static void el1_reset(dpeth_t * dep)
38433d6423SLionel Sambuc {
39*f7df02e7SDavid van Moolenbroek unsigned int ix;
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc for (ix = 0; ix < 8; ix += 1) /* Resets the board */
42433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RESET);
43433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
44433d6423SLionel Sambuc
45433d6423SLionel Sambuc /* Set Ethernet Address on controller */
46433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_LOOP); /* Loopback mode */
47433d6423SLionel Sambuc for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1)
48433d6423SLionel Sambuc outb_el1(dep, ix, StationAddress[ix]);
49433d6423SLionel Sambuc
50433d6423SLionel Sambuc /* Enable DMA/Interrupt, gain control of Buffer */
51433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
52433d6423SLionel Sambuc /* Clear RX packet area */
53433d6423SLionel Sambuc outw_el1(dep, EL1_RECVPTR, 0);
54433d6423SLionel Sambuc /* Enable transmit/receive configuration and flush pending interrupts */
55433d6423SLionel Sambuc outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER);
56433d6423SLionel Sambuc outb_el1(dep, EL1_RECV, dep->de_recv_mode);
57433d6423SLionel Sambuc inb_el1(dep, EL1_RECV);
58433d6423SLionel Sambuc inb_el1(dep, EL1_XMIT);
59433d6423SLionel Sambuc dep->de_flags &= NOT(DEF_XMIT_BUSY);
60433d6423SLionel Sambuc }
61433d6423SLionel Sambuc
62433d6423SLionel Sambuc /*
6391c4db25SDavid van Moolenbroek ** Name: el1_dumpstats
64433d6423SLionel Sambuc ** Function: Dumps counter on screen (support for console display).
65433d6423SLionel Sambuc */
el1_dumpstats(dpeth_t * UNUSED (dep))66433d6423SLionel Sambuc static void el1_dumpstats(dpeth_t * UNUSED(dep))
67433d6423SLionel Sambuc {
68433d6423SLionel Sambuc
69433d6423SLionel Sambuc }
70433d6423SLionel Sambuc
71433d6423SLionel Sambuc /*
7291c4db25SDavid van Moolenbroek ** Name: el1_mode_init
73433d6423SLionel Sambuc ** Function: Initializes receicer mode
74433d6423SLionel Sambuc */
el1_mode_init(dpeth_t * dep)75433d6423SLionel Sambuc static void el1_mode_init(dpeth_t * dep)
76433d6423SLionel Sambuc {
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc if (dep->de_flags & DEF_BROAD) {
79433d6423SLionel Sambuc dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK;
80433d6423SLionel Sambuc
81433d6423SLionel Sambuc } else if (dep->de_flags & DEF_PROMISC) {
82433d6423SLionel Sambuc dep->de_recv_mode = ERSR_ALL | ERSR_RMASK;
83433d6423SLionel Sambuc
84433d6423SLionel Sambuc } else if (dep->de_flags & DEF_MULTI) {
85433d6423SLionel Sambuc dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK;
86433d6423SLionel Sambuc
87433d6423SLionel Sambuc } else {
88433d6423SLionel Sambuc dep->de_recv_mode = ERSR_NONE | ERSR_RMASK;
89433d6423SLionel Sambuc }
90433d6423SLionel Sambuc outb_el1(dep, EL1_RECV, dep->de_recv_mode);
91433d6423SLionel Sambuc inb_el1(dep, EL1_RECV);
92433d6423SLionel Sambuc }
93433d6423SLionel Sambuc
94433d6423SLionel Sambuc /*
9591c4db25SDavid van Moolenbroek ** Name: el1_recv
96433d6423SLionel Sambuc ** Function: Receive function. Called from interrupt handler to
97433d6423SLionel Sambuc ** unload recv. buffer or from main (packet to client)
98433d6423SLionel Sambuc */
el1_recv(dpeth_t * dep,struct netdriver_data * data,size_t max)9991c4db25SDavid van Moolenbroek static ssize_t el1_recv(dpeth_t *dep, struct netdriver_data *data, size_t max)
100433d6423SLionel Sambuc {
101433d6423SLionel Sambuc buff_t *rxptr;
10291c4db25SDavid van Moolenbroek size_t size;
103433d6423SLionel Sambuc
10491c4db25SDavid van Moolenbroek if ((rxptr = dep->de_recvq_head) == NULL)
10591c4db25SDavid van Moolenbroek return SUSPEND;
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc /* Remove buffer from queue and free buffer */
108433d6423SLionel Sambuc if (dep->de_recvq_tail == dep->de_recvq_head)
109433d6423SLionel Sambuc dep->de_recvq_head = dep->de_recvq_tail = NULL;
110433d6423SLionel Sambuc else
111433d6423SLionel Sambuc dep->de_recvq_head = rxptr->next;
112433d6423SLionel Sambuc
113433d6423SLionel Sambuc /* Copy buffer to user area */
114*f7df02e7SDavid van Moolenbroek size = MIN((size_t)rxptr->size, max);
115433d6423SLionel Sambuc
11691c4db25SDavid van Moolenbroek netdriver_copyout(data, 0, rxptr->buffer, size);
117433d6423SLionel Sambuc
118433d6423SLionel Sambuc /* Return buffer to the idle pool */
119433d6423SLionel Sambuc free_buff(dep, rxptr);
12091c4db25SDavid van Moolenbroek
12191c4db25SDavid van Moolenbroek return size;
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc /*
12591c4db25SDavid van Moolenbroek ** Name: el1_send
12691c4db25SDavid van Moolenbroek ** Function: Send function.
127433d6423SLionel Sambuc */
el1_send(dpeth_t * dep,struct netdriver_data * data,size_t size)12891c4db25SDavid van Moolenbroek static int el1_send(dpeth_t *dep, struct netdriver_data *data, size_t size)
129433d6423SLionel Sambuc {
130433d6423SLionel Sambuc buff_t *txbuff;
131433d6423SLionel Sambuc clock_t now;
132433d6423SLionel Sambuc
13391c4db25SDavid van Moolenbroek if (dep->de_flags & DEF_XMIT_BUSY) {
134d91f738bSDavid van Moolenbroek now = getticks();
135433d6423SLionel Sambuc if ((now - dep->de_xmit_start) > 4) {
136433d6423SLionel Sambuc /* Transmitter timed out */
137433d6423SLionel Sambuc DEBUG(printf("3c501: transmitter timed out ... \n"));
138*f7df02e7SDavid van Moolenbroek netdriver_stat_oerror(1);
139433d6423SLionel Sambuc dep->de_flags &= NOT(DEF_XMIT_BUSY);
14091c4db25SDavid van Moolenbroek /* Try sending anyway. */
14191c4db25SDavid van Moolenbroek } else
14291c4db25SDavid van Moolenbroek return SUSPEND;
143433d6423SLionel Sambuc }
144433d6423SLionel Sambuc
14591c4db25SDavid van Moolenbroek /* Since we may have to retransmit, we need a local copy. */
14691c4db25SDavid van Moolenbroek if ((txbuff = alloc_buff(dep, size + sizeof(buff_t))) == NULL)
14791c4db25SDavid van Moolenbroek panic("out of memory");
14891c4db25SDavid van Moolenbroek
14991c4db25SDavid van Moolenbroek /* Fill transmit buffer from user area */
15091c4db25SDavid van Moolenbroek txbuff->next = NULL;
15191c4db25SDavid van Moolenbroek txbuff->size = size;
15291c4db25SDavid van Moolenbroek
15391c4db25SDavid van Moolenbroek netdriver_copyin(data, 0, txbuff->buffer, size);
15491c4db25SDavid van Moolenbroek
155433d6423SLionel Sambuc /* Save for retransmission */
156433d6423SLionel Sambuc TxBuff = txbuff;
15791c4db25SDavid van Moolenbroek dep->de_flags |= DEF_XMIT_BUSY;
158433d6423SLionel Sambuc
159433d6423SLionel Sambuc /* Setup board for packet loading */
160433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
161433d6423SLionel Sambuc inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */
162433d6423SLionel Sambuc inb_el1(dep, EL1_XMIT);
163433d6423SLionel Sambuc outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */
164433d6423SLionel Sambuc
165433d6423SLionel Sambuc /* Loads packet */
16691c4db25SDavid van Moolenbroek outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size));
16791c4db25SDavid van Moolenbroek outsb(dep->de_data_port, txbuff->buffer, size);
168433d6423SLionel Sambuc /* Starts transmitter */
16991c4db25SDavid van Moolenbroek outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size));
170433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */
171433d6423SLionel Sambuc
172d91f738bSDavid van Moolenbroek dep->de_xmit_start = getticks();
17391c4db25SDavid van Moolenbroek
17491c4db25SDavid van Moolenbroek return OK;
175433d6423SLionel Sambuc }
176433d6423SLionel Sambuc
177433d6423SLionel Sambuc /*
17891c4db25SDavid van Moolenbroek ** Name: el1_stop
179433d6423SLionel Sambuc ** Function: Stops board and disable interrupts.
180433d6423SLionel Sambuc */
el1_stop(dpeth_t * dep)181433d6423SLionel Sambuc static void el1_stop(dpeth_t * dep)
182433d6423SLionel Sambuc {
183433d6423SLionel Sambuc int ix;
184433d6423SLionel Sambuc
185*f7df02e7SDavid van Moolenbroek DEBUG(printf("%s: stopping Etherlink ....\n", netdriver_name()));
186433d6423SLionel Sambuc for (ix = 0; ix < 8; ix += 1) /* Reset board */
187433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RESET);
188433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_SYS);
189433d6423SLionel Sambuc sys_irqdisable(&dep->de_hook); /* Disable interrupt */
190433d6423SLionel Sambuc }
191433d6423SLionel Sambuc
192433d6423SLionel Sambuc /*
19391c4db25SDavid van Moolenbroek ** Name: el1_interrupt
194433d6423SLionel Sambuc ** Function: Interrupt handler. Acknwledges transmit interrupts
195433d6423SLionel Sambuc ** or unloads receive buffer to memory queue.
196433d6423SLionel Sambuc */
el1_interrupt(dpeth_t * dep)197433d6423SLionel Sambuc static void el1_interrupt(dpeth_t * dep)
198433d6423SLionel Sambuc {
199433d6423SLionel Sambuc u16_t csr, isr;
200433d6423SLionel Sambuc int pktsize;
201433d6423SLionel Sambuc buff_t *rxptr;
202433d6423SLionel Sambuc
203433d6423SLionel Sambuc csr = inb_el1(dep, EL1_CSR);
204433d6423SLionel Sambuc if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) {
205433d6423SLionel Sambuc
206433d6423SLionel Sambuc /* Got a transmit interrupt */
207433d6423SLionel Sambuc isr = inb_el1(dep, EL1_XMIT);
208433d6423SLionel Sambuc if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) {
209433d6423SLionel Sambuc DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr));
210433d6423SLionel Sambuc if (isr & EXSR_JAM) {
211433d6423SLionel Sambuc /* Sending, packet got a collision */
212*f7df02e7SDavid van Moolenbroek netdriver_stat_coll(1);
213433d6423SLionel Sambuc /* Put pointer back to beginning of packet */
214433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
215433d6423SLionel Sambuc outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size));
216433d6423SLionel Sambuc /* And retrigger transmission */
217433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);
218433d6423SLionel Sambuc return;
219433d6423SLionel Sambuc
220433d6423SLionel Sambuc } else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) {
221*f7df02e7SDavid van Moolenbroek netdriver_stat_oerror(1);
222433d6423SLionel Sambuc } else if (isr & EXSR_UNDER) {
223*f7df02e7SDavid van Moolenbroek netdriver_stat_oerror(1);
224433d6423SLionel Sambuc }
225433d6423SLionel Sambuc DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr));
226433d6423SLionel Sambuc el1_reset(dep);
227433d6423SLionel Sambuc } else {
228433d6423SLionel Sambuc /** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/
229433d6423SLionel Sambuc /* Packet transmitted successfully */
230433d6423SLionel Sambuc dep->bytes_Tx += (long) (TxBuff->size);
231433d6423SLionel Sambuc free_buff(dep, TxBuff);
232433d6423SLionel Sambuc dep->de_flags &= NOT(DEF_XMIT_BUSY);
23391c4db25SDavid van Moolenbroek netdriver_send();
23491c4db25SDavid van Moolenbroek if (dep->de_flags & DEF_XMIT_BUSY)
235433d6423SLionel Sambuc return;
236433d6423SLionel Sambuc }
237433d6423SLionel Sambuc
238433d6423SLionel Sambuc } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) {
239433d6423SLionel Sambuc
240433d6423SLionel Sambuc /* Got a receive interrupt */
241433d6423SLionel Sambuc isr = inb_el1(dep, EL1_RECV);
242433d6423SLionel Sambuc pktsize = inw_el1(dep, EL1_RECVPTR);
243433d6423SLionel Sambuc if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) {
244*f7df02e7SDavid van Moolenbroek DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n",
245*f7df02e7SDavid van Moolenbroek csr, isr, pktsize));
246*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(1);
247433d6423SLionel Sambuc
248*f7df02e7SDavid van Moolenbroek } else if (pktsize < NDEV_ETH_PACKET_MIN ||
249*f7df02e7SDavid van Moolenbroek pktsize > NDEV_ETH_PACKET_MAX) {
250*f7df02e7SDavid van Moolenbroek DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n",
251*f7df02e7SDavid van Moolenbroek csr, isr, pktsize));
252*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(1);
253433d6423SLionel Sambuc
254433d6423SLionel Sambuc } else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) {
255433d6423SLionel Sambuc /* Memory not available. Drop packet */
256*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(1);
257433d6423SLionel Sambuc
258433d6423SLionel Sambuc } else if (isr & (ERSR_GOOD | ERSR_ANY)) {
259433d6423SLionel Sambuc /* Got a good packet. Read it from buffer */
260433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
261433d6423SLionel Sambuc outw_el1(dep, EL1_XMITPTR, 0);
26291c4db25SDavid van Moolenbroek insb(dep->de_data_port, rxptr->buffer, pktsize);
263433d6423SLionel Sambuc rxptr->next = NULL;
264433d6423SLionel Sambuc rxptr->size = pktsize;
265433d6423SLionel Sambuc dep->bytes_Rx += (long) pktsize;
26691c4db25SDavid van Moolenbroek /* Queue packet to receive queue */
267433d6423SLionel Sambuc if (dep->de_recvq_head == NULL)
268433d6423SLionel Sambuc dep->de_recvq_head = rxptr;
269433d6423SLionel Sambuc else
270433d6423SLionel Sambuc dep->de_recvq_tail->next = rxptr;
271433d6423SLionel Sambuc dep->de_recvq_tail = rxptr;
272433d6423SLionel Sambuc
273433d6423SLionel Sambuc /* Reply to pending Receive requests, if any */
27491c4db25SDavid van Moolenbroek netdriver_recv();
275433d6423SLionel Sambuc }
276433d6423SLionel Sambuc } else { /* Nasty condition, should never happen */
277433d6423SLionel Sambuc DEBUG(
278433d6423SLionel Sambuc printf("3c501: got interrupt with status 0x%02X\n"
279433d6423SLionel Sambuc " de_flags=0x%04X XSR=0x%02X RSR=0x%02X \n"
280433d6423SLionel Sambuc " xmit buffer = 0x%4X recv buffer = 0x%4X\n",
281433d6423SLionel Sambuc csr, dep->de_flags,
282433d6423SLionel Sambuc inb_el1(dep, EL1_RECV),
283433d6423SLionel Sambuc inb_el1(dep, EL1_XMIT),
284433d6423SLionel Sambuc inw_el1(dep, EL1_XMITPTR),
285433d6423SLionel Sambuc inw_el1(dep, EL1_RECVPTR))
286433d6423SLionel Sambuc );
287433d6423SLionel Sambuc el1_reset(dep);
288433d6423SLionel Sambuc }
289433d6423SLionel Sambuc
290433d6423SLionel Sambuc /* Move into receive mode */
291433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
292433d6423SLionel Sambuc outw_el1(dep, EL1_RECVPTR, 0);
293433d6423SLionel Sambuc /* Be sure that interrupts are cleared */
294433d6423SLionel Sambuc inb_el1(dep, EL1_RECV);
295433d6423SLionel Sambuc inb_el1(dep, EL1_XMIT);
296433d6423SLionel Sambuc }
297433d6423SLionel Sambuc
298433d6423SLionel Sambuc /*
29991c4db25SDavid van Moolenbroek ** Name: el1_init
300433d6423SLionel Sambuc ** Function: Initalizes board hardware and driver data structures.
301433d6423SLionel Sambuc */
el1_init(dpeth_t * dep)302433d6423SLionel Sambuc static void el1_init(dpeth_t * dep)
303433d6423SLionel Sambuc {
304*f7df02e7SDavid van Moolenbroek unsigned int ix;
305433d6423SLionel Sambuc
306433d6423SLionel Sambuc dep->de_irq &= NOT(DEI_DEFAULT); /* Strip the default flag. */
307433d6423SLionel Sambuc dep->de_offset_page = 0;
308433d6423SLionel Sambuc dep->de_data_port = dep->de_base_port + EL1_DATAPORT;
309433d6423SLionel Sambuc
310433d6423SLionel Sambuc el1_reset(dep); /* Reset and initialize board */
311433d6423SLionel Sambuc
312433d6423SLionel Sambuc /* Start receiver (default mode) */
313433d6423SLionel Sambuc outw_el1(dep, EL1_RECVPTR, 0);
314433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
315433d6423SLionel Sambuc
316433d6423SLionel Sambuc /* Initializes buffer pool */
317433d6423SLionel Sambuc init_buff(dep, NULL);
318433d6423SLionel Sambuc el1_mode_init(dep);
319433d6423SLionel Sambuc
320433d6423SLionel Sambuc printf("%s: Etherlink (%s) at %X:%d - ",
321*f7df02e7SDavid van Moolenbroek netdriver_name(), "3c501", dep->de_base_port, dep->de_irq);
322433d6423SLionel Sambuc for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
323*f7df02e7SDavid van Moolenbroek printf("%02X%c", (dep->de_address.na_addr[ix] = StationAddress[ix]),
324433d6423SLionel Sambuc ix < SA_ADDR_LEN - 1 ? ':' : '\n');
325433d6423SLionel Sambuc
326433d6423SLionel Sambuc /* Device specific functions */
327433d6423SLionel Sambuc dep->de_recvf = el1_recv;
328433d6423SLionel Sambuc dep->de_sendf = el1_send;
329433d6423SLionel Sambuc dep->de_flagsf = el1_mode_init;
330433d6423SLionel Sambuc dep->de_resetf = el1_reset;
331433d6423SLionel Sambuc dep->de_getstatsf = el1_getstats;
332433d6423SLionel Sambuc dep->de_dumpstatsf = el1_dumpstats;
333433d6423SLionel Sambuc dep->de_interruptf = el1_interrupt;
334433d6423SLionel Sambuc }
335433d6423SLionel Sambuc
336433d6423SLionel Sambuc /*
33791c4db25SDavid van Moolenbroek ** Name: el1_probe
338433d6423SLionel Sambuc ** Function: Checks for presence of the board.
339433d6423SLionel Sambuc */
el1_probe(dpeth_t * dep)340433d6423SLionel Sambuc int el1_probe(dpeth_t * dep)
341433d6423SLionel Sambuc {
342*f7df02e7SDavid van Moolenbroek unsigned int ix;
343433d6423SLionel Sambuc
344433d6423SLionel Sambuc for (ix = 0; ix < 8; ix += 1) /* Reset the board */
345433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RESET);
346433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_SYS); /* Leaves buffer to system */
347433d6423SLionel Sambuc
348433d6423SLionel Sambuc /* Check station address */
349433d6423SLionel Sambuc for (ix = 0; ix < SA_ADDR_LEN; ix += 1) {
350433d6423SLionel Sambuc outw_el1(dep, EL1_XMITPTR, ix);
351433d6423SLionel Sambuc StationAddress[ix] = inb_el1(dep, EL1_SAPROM);
352433d6423SLionel Sambuc }
353433d6423SLionel Sambuc if (StationAddress[0] != 0x02 || /* Etherlink Station address */
354433d6423SLionel Sambuc StationAddress[1] != 0x60 || /* MUST be 02:60:8c:xx:xx:xx */
355433d6423SLionel Sambuc StationAddress[2] != 0x8C)
356433d6423SLionel Sambuc return FALSE; /* No Etherlink board at this address */
357433d6423SLionel Sambuc
358433d6423SLionel Sambuc dep->de_ramsize = 0; /* RAM size is meaningless */
359433d6423SLionel Sambuc dep->de_linmem = 0L; /* Access is via I/O port */
360433d6423SLionel Sambuc
361433d6423SLionel Sambuc /* Device specific functions */
362433d6423SLionel Sambuc dep->de_initf = el1_init;
363433d6423SLionel Sambuc dep->de_stopf = el1_stop;
364433d6423SLionel Sambuc
365433d6423SLionel Sambuc return TRUE; /* Etherlink board found */
366433d6423SLionel Sambuc }
367433d6423SLionel Sambuc
368433d6423SLionel Sambuc #endif /* ENABLE_3C501 */
369433d6423SLionel Sambuc
370433d6423SLionel Sambuc /** 3c501.c **/
371