iso9660fs: initialize buffer cache
[minix.git] / drivers / dpeth / 3c501.c
blob429ea5844150e70f93ad3b07972d42fd8936bd47
1 /*
2 ** File: 3c501.c Jan. 14, 1997
3 **
4 ** Author: Giovanni Falzoni <gfalzoni@inwind.it>
5 **
6 ** This file contains specific implementation of the ethernet
7 ** device driver for 3Com Etherlink (3c501) boards. This is a
8 ** very old board and its performances are very poor for today
9 ** network environments.
12 #include <minix/drivers.h>
13 #include <minix/com.h>
14 #include <net/gen/ether.h>
15 #include <net/gen/eth_io.h>
16 #include "dp.h"
18 #if (ENABLE_3C501 == 1)
20 #include "3c501.h"
22 static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,};
23 static buff_t *TxBuff = NULL;
26 ** Name: void el1_getstats(dpeth_t *dep)
27 ** Function: Reads statistics counters from board.
28 **/
29 static void el1_getstats(dpeth_t * dep)
32 return; /* Nothing to do */
36 ** Name: void el1_reset(dpeth_t *dep)
37 ** Function: Reset function specific for Etherlink hardware.
39 static void el1_reset(dpeth_t * dep)
41 int ix;
43 for (ix = 0; ix < 8; ix += 1) /* Resets the board */
44 outb_el1(dep, EL1_CSR, ECSR_RESET);
45 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
47 /* Set Ethernet Address on controller */
48 outb_el1(dep, EL1_CSR, ECSR_LOOP); /* Loopback mode */
49 for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1)
50 outb_el1(dep, ix, StationAddress[ix]);
52 lock();
53 /* Enable DMA/Interrupt, gain control of Buffer */
54 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
55 /* Clear RX packet area */
56 outw_el1(dep, EL1_RECVPTR, 0);
57 /* Enable transmit/receive configuration and flush pending interrupts */
58 outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER);
59 outb_el1(dep, EL1_RECV, dep->de_recv_mode);
60 inb_el1(dep, EL1_RECV);
61 inb_el1(dep, EL1_XMIT);
62 dep->de_flags &= NOT(DEF_XMIT_BUSY);
63 unlock();
64 return; /* Done */
68 ** Name: void el1_dumpstats(dpeth_t *dep, int port, vir_bytes size)
69 ** Function: Dumps counter on screen (support for console display).
71 static void el1_dumpstats(dpeth_t * UNUSED(dep))
74 return;
78 ** Name: void el1_mode_init(dpeth_t *dep)
79 ** Function: Initializes receicer mode
81 static void el1_mode_init(dpeth_t * dep)
84 if (dep->de_flags & DEF_BROAD) {
85 dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK;
87 } else if (dep->de_flags & DEF_PROMISC) {
88 dep->de_recv_mode = ERSR_ALL | ERSR_RMASK;
90 } else if (dep->de_flags & DEF_MULTI) {
91 dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK;
93 } else {
94 dep->de_recv_mode = ERSR_NONE | ERSR_RMASK;
96 outb_el1(dep, EL1_RECV, dep->de_recv_mode);
97 inb_el1(dep, EL1_RECV);
98 return;
102 ** Name: void el1_recv(dpeth_t *dep, int from, int size)
103 ** Function: Receive function. Called from interrupt handler to
104 ** unload recv. buffer or from main (packet to client)
106 static void el1_recv(dpeth_t * dep, int from, int size)
108 buff_t *rxptr;
110 while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) {
112 /* Remove buffer from queue and free buffer */
113 lock();
114 if (dep->de_recvq_tail == dep->de_recvq_head)
115 dep->de_recvq_head = dep->de_recvq_tail = NULL;
116 else
117 dep->de_recvq_head = rxptr->next;
118 unlock();
120 /* Copy buffer to user area */
121 mem2user(dep, rxptr);
123 /* Reply information */
124 dep->de_read_s = rxptr->size;
125 dep->de_flags |= DEF_ACK_RECV;
126 dep->de_flags &= NOT(DEF_READING);
128 /* Return buffer to the idle pool */
129 free_buff(dep, rxptr);
131 return;
135 ** Name: void el1_send(dpeth_t *dep, int from_int, int pktsize)
136 ** Function: Send function. Called from main to transit a packet or
137 ** from interrupt handler when a new packet was queued.
139 static void el1_send(dpeth_t * dep, int from_int, int pktsize)
141 buff_t *txbuff;
142 clock_t now;
144 if (from_int == FALSE) {
146 if ((txbuff = alloc_buff(dep, pktsize + sizeof(buff_t))) != NULL) {
148 /* Fill transmit buffer from user area */
149 txbuff->next = NULL;
150 txbuff->size = pktsize;
151 txbuff->client = dep->de_client;
152 user2mem(dep, txbuff);
153 } else
154 panic("out of memory for Tx");
156 } else if ((txbuff = dep->de_xmitq_head) != NULL) {
158 /* Get first packet in queue */
159 lock();
160 if (dep->de_xmitq_tail == dep->de_xmitq_head)
161 dep->de_xmitq_head = dep->de_xmitq_tail = NULL;
162 else
163 dep->de_xmitq_head = txbuff->next;
164 unlock();
165 pktsize = txbuff->size;
167 } else
168 panic("should not be sending ");
170 if ((dep->de_flags & DEF_XMIT_BUSY)) {
171 if (from_int) panic("should not be sending ");
172 getuptime(&now);
173 if ((now - dep->de_xmit_start) > 4) {
174 /* Transmitter timed out */
175 DEBUG(printf("3c501: transmitter timed out ... \n"));
176 dep->de_stat.ets_sendErr += 1;
177 dep->de_flags &= NOT(DEF_XMIT_BUSY);
178 el1_reset(dep);
181 /* Queue packet */
182 lock(); /* Queue packet to receive queue */
183 if (dep->de_xmitq_head == NULL)
184 dep->de_xmitq_head = txbuff;
185 else
186 dep->de_xmitq_tail->next = txbuff;
187 dep->de_xmitq_tail = txbuff;
188 unlock();
189 } else {
190 /* Save for retransmission */
191 TxBuff = txbuff;
192 dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
194 /* Setup board for packet loading */
195 lock(); /* Buffer to processor */
196 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
197 inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */
198 inb_el1(dep, EL1_XMIT);
199 outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */
201 /* Loads packet */
202 outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
203 outsb(dep->de_data_port, SELF, txbuff->buffer, pktsize);
204 /* Starts transmitter */
205 outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
206 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */
207 unlock();
209 getuptime(&dep->de_xmit_start);
210 dep->de_flags &= NOT(DEF_SENDING);
212 return;
216 ** Name: void el1_stop(dpeth_t *dep)
217 ** Function: Stops board and disable interrupts.
219 static void el1_stop(dpeth_t * dep)
221 int ix;
223 DEBUG(printf("%s: stopping Etherlink ....\n", dep->de_name));
224 for (ix = 0; ix < 8; ix += 1) /* Reset board */
225 outb_el1(dep, EL1_CSR, ECSR_RESET);
226 outb_el1(dep, EL1_CSR, ECSR_SYS);
227 sys_irqdisable(&dep->de_hook); /* Disable interrupt */
228 return;
232 ** Name: void el1_interrupt(dpeth_t *dep)
233 ** Function: Interrupt handler. Acknwledges transmit interrupts
234 ** or unloads receive buffer to memory queue.
236 static void el1_interrupt(dpeth_t * dep)
238 u16_t csr, isr;
239 int pktsize;
240 buff_t *rxptr;
242 csr = inb_el1(dep, EL1_CSR);
243 if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) {
245 /* Got a transmit interrupt */
246 isr = inb_el1(dep, EL1_XMIT);
247 if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) {
248 DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr));
249 if (isr & EXSR_JAM) {
250 /* Sending, packet got a collision */
251 dep->de_stat.ets_collision += 1;
252 /* Put pointer back to beginning of packet */
253 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
254 outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size));
255 /* And retrigger transmission */
256 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);
257 return;
259 } else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) {
260 dep->de_stat.ets_sendErr += 1;
262 } else if (isr & EXSR_UNDER) {
263 dep->de_stat.ets_fifoUnder += 1;
265 DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr));
266 el1_reset(dep);
268 } else {
269 /** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/
270 /* Packet transmitted successfully */
271 dep->de_stat.ets_packetT += 1;
272 dep->bytes_Tx += (long) (TxBuff->size);
273 free_buff(dep, TxBuff);
274 dep->de_flags &= NOT(DEF_XMIT_BUSY);
275 if ((dep->de_flags & DEF_SENDING) && dep->de_xmitq_head) {
276 /* Pending transmit request available in queue */
277 el1_send(dep, TRUE, 0);
278 if (dep->de_flags & (DEF_XMIT_BUSY | DEF_ACK_SEND))
279 return;
283 } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) {
285 /* Got a receive interrupt */
286 isr = inb_el1(dep, EL1_RECV);
287 pktsize = inw_el1(dep, EL1_RECVPTR);
288 if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) {
289 DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
290 dep->de_stat.ets_recvErr += 1;
292 } else if (pktsize < ETH_MIN_PACK_SIZE || pktsize > ETH_MAX_PACK_SIZE) {
293 DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
294 dep->de_stat.ets_recvErr += 1;
296 } else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) {
297 /* Memory not available. Drop packet */
298 dep->de_stat.ets_fifoOver += 1;
300 } else if (isr & (ERSR_GOOD | ERSR_ANY)) {
301 /* Got a good packet. Read it from buffer */
302 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
303 outw_el1(dep, EL1_XMITPTR, 0);
304 insb(dep->de_data_port, SELF, rxptr->buffer, pktsize);
305 rxptr->next = NULL;
306 rxptr->size = pktsize;
307 dep->de_stat.ets_packetR += 1;
308 dep->bytes_Rx += (long) pktsize;
309 lock(); /* Queue packet to receive queue */
310 if (dep->de_recvq_head == NULL)
311 dep->de_recvq_head = rxptr;
312 else
313 dep->de_recvq_tail->next = rxptr;
314 dep->de_recvq_tail = rxptr;
315 unlock();
317 /* Reply to pending Receive requests, if any */
318 el1_recv(dep, TRUE, 0);
320 } else { /* Nasty condition, should never happen */
321 DEBUG(
322 printf("3c501: got interrupt with status 0x%02X\n"
323 " de_flags=0x%04X XSR=0x%02X RSR=0x%02X \n"
324 " xmit buffer = 0x%4X recv buffer = 0x%4X\n",
325 csr, dep->de_flags,
326 inb_el1(dep, EL1_RECV),
327 inb_el1(dep, EL1_XMIT),
328 inw_el1(dep, EL1_XMITPTR),
329 inw_el1(dep, EL1_RECVPTR))
331 el1_reset(dep);
334 /* Move into receive mode */
335 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
336 outw_el1(dep, EL1_RECVPTR, 0);
337 /* Be sure that interrupts are cleared */
338 inb_el1(dep, EL1_RECV);
339 inb_el1(dep, EL1_XMIT);
340 return;
344 ** Name: void el1_init(dpeth_t *dep)
345 ** Function: Initalizes board hardware and driver data structures.
347 static void el1_init(dpeth_t * dep)
349 int ix;
351 dep->de_irq &= NOT(DEI_DEFAULT); /* Strip the default flag. */
352 dep->de_offset_page = 0;
353 dep->de_data_port = dep->de_base_port + EL1_DATAPORT;
355 el1_reset(dep); /* Reset and initialize board */
357 /* Start receiver (default mode) */
358 outw_el1(dep, EL1_RECVPTR, 0);
359 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
361 /* Initializes buffer pool */
362 init_buff(dep, NULL);
363 el1_mode_init(dep);
365 printf("%s: Etherlink (%s) at %X:%d - ",
366 dep->de_name, "3c501", dep->de_base_port, dep->de_irq);
367 for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
368 printf("%02X%c", (dep->de_address.ea_addr[ix] = StationAddress[ix]),
369 ix < SA_ADDR_LEN - 1 ? ':' : '\n');
371 /* Device specific functions */
372 dep->de_recvf = el1_recv;
373 dep->de_sendf = el1_send;
374 dep->de_flagsf = el1_mode_init;
375 dep->de_resetf = el1_reset;
376 dep->de_getstatsf = el1_getstats;
377 dep->de_dumpstatsf = el1_dumpstats;
378 dep->de_interruptf = el1_interrupt;
380 return; /* Done */
384 ** Name: int el1_probe(dpeth_t *dep)
385 ** Function: Checks for presence of the board.
387 int el1_probe(dpeth_t * dep)
389 int ix;
391 for (ix = 0; ix < 8; ix += 1) /* Reset the board */
392 outb_el1(dep, EL1_CSR, ECSR_RESET);
393 outb_el1(dep, EL1_CSR, ECSR_SYS); /* Leaves buffer to system */
395 /* Check station address */
396 for (ix = 0; ix < SA_ADDR_LEN; ix += 1) {
397 outw_el1(dep, EL1_XMITPTR, ix);
398 StationAddress[ix] = inb_el1(dep, EL1_SAPROM);
400 if (StationAddress[0] != 0x02 || /* Etherlink Station address */
401 StationAddress[1] != 0x60 || /* MUST be 02:60:8c:xx:xx:xx */
402 StationAddress[2] != 0x8C)
403 return FALSE; /* No Etherlink board at this address */
405 dep->de_ramsize = 0; /* RAM size is meaningless */
406 dep->de_linmem = 0L; /* Access is via I/O port */
408 /* Device specific functions */
409 dep->de_initf = el1_init;
410 dep->de_stopf = el1_stop;
412 return TRUE; /* Etherlink board found */
415 #endif /* ENABLE_3C501 */
417 /** 3c501.c **/