unstack - fix ipcvecs
[minix.git] / sys / arch / i386 / stand / lib / netif / elink3.c
blob1a115d47d787b6b7d733ac01ee6a09d04bd56d4e
1 /* $NetBSD: elink3.c,v 1.4 2008/12/14 18:46:33 christos Exp $ */
3 /* stripped down from freebsd:sys/i386/netboot/3c509.c */
5 /**************************************************************************
6 NETBOOT - BOOTP/TFTP Bootstrap Program
8 Author: Martin Renters.
9 Date: Mar 22 1995
11 This code is based heavily on David Greenman's if_ed.c driver and
12 Andres Vega Garcia's if_ep.c driver.
14 Copyright (C) 1993-1994, David Greenman, Martin Renters.
15 Copyright (C) 1993-1995, Andres Vega Garcia.
16 Copyright (C) 1995, Serge Babkin.
17 This software may be used, modified, copied, distributed, and sold, in
18 both source and binary form provided that the above copyright and these
19 terms are retained. Under no circumstances are the authors responsible for
20 the proper functioning of this software, nor do the authors assume any
21 responsibility for damages incurred with its use.
23 3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
25 3c509.c,v 1.2 1995/05/30 07:58:52 rgrimes Exp
27 ***************************************************************************/
29 #include <sys/types.h>
30 #include <machine/pio.h>
32 #include <lib/libsa/stand.h>
34 #include <libi386.h>
36 #include "etherdrv.h"
37 #include "3c509.h"
39 extern unsigned short eth_base;
41 extern u_char eth_myaddr[6];
43 void
44 epstop(void)
47 /* stop card */
48 outw(BASE + EP_COMMAND, RX_DISABLE);
49 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
50 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
52 outw(BASE + EP_COMMAND, TX_DISABLE);
53 outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
55 outw(BASE + EP_COMMAND, RX_RESET);
56 outw(BASE + EP_COMMAND, TX_RESET);
58 outw(BASE + EP_COMMAND, C_INTR_LATCH);
59 outw(BASE + EP_COMMAND, SET_RD_0_MASK);
60 outw(BASE + EP_COMMAND, SET_INTR_MASK);
61 outw(BASE + EP_COMMAND, SET_RX_FILTER);
64 void
65 EtherStop(void)
68 epstop();
69 outw(BASE + EP_COMMAND, GLOBAL_RESET);
70 delay(100000);
73 /**************************************************************************
74 ETH_RESET - Reset adapter
75 ***************************************************************************/
76 void
77 epreset(void)
79 int i;
81 /***********************************************************
82 Reset 3Com 509 card
83 *************************************************************/
85 epstop();
88 * initialize card
90 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
91 continue;
93 GO_WINDOW(0);
95 /* Disable the card */
96 outw(BASE + EP_W0_CONFIG_CTRL, 0);
98 /* Configure IRQ to none */
99 outw(BASE + EP_W0_RESOURCE_CFG, SET_IRQ(0));
101 /* Enable the card */
102 outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
104 GO_WINDOW(2);
106 /* Reload the ether_addr. */
107 for (i = 0; i < 6; i++)
108 outb(BASE + EP_W2_ADDR_0 + i, eth_myaddr[i]);
110 outw(BASE + EP_COMMAND, RX_RESET);
111 outw(BASE + EP_COMMAND, TX_RESET);
113 /* Window 1 is operating window */
114 GO_WINDOW(1);
115 for (i = 0; i < 31; i++)
116 inb(BASE + EP_W1_TX_STATUS);
118 /* get rid of stray intr's */
119 outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
121 outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS);
123 outw(BASE + EP_COMMAND, SET_INTR_MASK);
125 outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
126 FIL_BRDCST);
128 /* configure BNC */
129 if (ether_medium == ETHERMEDIUM_BNC) {
130 outw(BASE + EP_COMMAND, START_TRANSCEIVER);
131 delay(1000);
133 /* configure UTP */
134 if (ether_medium == ETHERMEDIUM_UTP) {
135 GO_WINDOW(4);
136 outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
137 GO_WINDOW(1);
140 /* start tranciever and receiver */
141 outw(BASE + EP_COMMAND, RX_ENABLE);
142 outw(BASE + EP_COMMAND, TX_ENABLE);
144 /* set early threshold for minimal packet length */
145 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | 64);
147 outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16);
150 /**************************************************************************
151 ETH_TRANSMIT - Transmit a frame
152 ***************************************************************************/
153 static const char padmap[] = {
154 0, 3, 2, 1};
157 EtherSend(char *pkt, int len)
159 int pad;
160 int status;
162 #ifdef EDEBUG
163 printf("{l=%d}", len);
164 #endif
166 pad = padmap[len & 3];
169 * The 3c509 automatically pads short packets to minimum ethernet length,
170 * but we drop packets that are too large. Perhaps we should truncate
171 * them instead?
173 if (len + pad > ETHER_MAX_LEN) {
174 return -1;
177 /* drop acknowledgements */
178 while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
179 if (status & (TXS_UNDERRUN | TXS_MAX_COLLISION |
180 TXS_STATUS_OVERFLOW)) {
181 outw(BASE + EP_COMMAND, TX_RESET);
182 outw(BASE + EP_COMMAND, TX_ENABLE);
185 outb(BASE + EP_W1_TX_STATUS, 0x0);
188 while (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
189 /* no room in FIFO */
190 continue;
193 outw(BASE + EP_W1_TX_PIO_WR_1, len);
194 outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */
196 /* write packet */
197 outsw(BASE + EP_W1_TX_PIO_WR_1, pkt, len / 2);
198 if (len & 1)
199 outb(BASE + EP_W1_TX_PIO_WR_1, *(pkt + len - 1));
201 while (pad--)
202 outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
204 /* timeout after sending */
205 delay(1000);
206 return len;
209 /**************************************************************************
210 ETH_POLL - Wait for a frame
211 ***************************************************************************/
213 EtherReceive(char *pkt, int maxlen)
215 /* common variables */
216 int len;
217 /* variables for 3C509 */
218 short status, cst;
219 register short rx_fifo;
221 cst = inw(BASE + EP_STATUS);
223 #ifdef EDEBUG
224 if (cst & 0x1FFF)
225 printf("-%x-",cst);
226 #endif
228 if ((cst & (S_RX_COMPLETE|S_RX_EARLY)) == 0) {
229 /* acknowledge everything */
230 outw(BASE + EP_COMMAND, ACK_INTR| (cst & S_5_INTS));
231 outw(BASE + EP_COMMAND, C_INTR_LATCH);
233 return 0;
236 status = inw(BASE + EP_W1_RX_STATUS);
237 #ifdef EDEBUG
238 printf("*%x*",status);
239 #endif
241 if (status & ERR_RX) {
242 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
243 return 0;
246 rx_fifo = status & RX_BYTES_MASK;
247 if (rx_fifo == 0)
248 return 0;
250 if (rx_fifo > maxlen)
251 goto zulang;
253 /* read packet */
254 #ifdef EDEBUG
255 printf("[l=%d",rx_fifo);
256 #endif
257 insw(BASE + EP_W1_RX_PIO_RD_1, pkt, rx_fifo / 2);
258 if (rx_fifo & 1)
259 pkt[rx_fifo-1] = inb(BASE + EP_W1_RX_PIO_RD_1);
260 len = rx_fifo;
262 for (;;) {
263 status = inw(BASE + EP_W1_RX_STATUS);
264 #ifdef EDEBUG
265 printf("*%x*",status);
266 #endif
267 rx_fifo = status & RX_BYTES_MASK;
269 if (rx_fifo > 0) {
270 if ((len + rx_fifo) > maxlen)
271 goto zulang;
273 insw(BASE + EP_W1_RX_PIO_RD_1, pkt + len, rx_fifo / 2);
274 if (rx_fifo & 1)
275 pkt[len + rx_fifo-1] = inb(BASE + EP_W1_RX_PIO_RD_1);
276 len += rx_fifo;
277 #ifdef EDEBUG
278 printf("+%d",rx_fifo);
279 #endif
282 if ((status & RX_INCOMPLETE) == 0) {
283 #ifdef EDEBUG
284 printf("=%d",len);
285 #endif
286 break;
289 delay(1000);
292 /* acknowledge reception of packet */
293 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
294 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
295 continue;
297 return len;
299 zulang:
300 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
301 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
302 continue;
303 return 0;
306 /*************************************************************************
307 3Com 509 - specific routines
308 **************************************************************************/
310 static int
311 eeprom_rdy(void)
313 int i;
315 for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++);
316 if (i >= MAX_EEPROMBUSY) {
317 printf("3c509: eeprom failed to come ready.\r\n");
318 return 0;
320 return 1;
324 * get_e: gets a 16 bits word from the EEPROM. we must have set the window
325 * before
328 ep_get_e(int offset)
330 if (!eeprom_rdy())
331 return 0xffff;
332 outw(IS_BASE + EP_W0_EEPROM_COMMAND, EEPROM_CMD_RD | offset);
333 if (!eeprom_rdy())
334 return 0xffff;
335 return inw(IS_BASE + EP_W0_EEPROM_DATA);