eth_ntoa and warnings fixups
[people/xl0/gpxe.git] / src / drivers / net / ns8390.c
1 /**************************************************************************
2 ETHERBOOT -  BOOTP/TFTP Bootstrap Program
3
4 Author: Martin Renters
5   Date: May/94
6
7  This code is based heavily on David Greenman's if_ed.c driver
8
9  Copyright (C) 1993-1994, David Greenman, Martin Renters.
10   This software may be used, modified, copied, distributed, and sold, in
11   both source and binary form provided that the above copyright and these
12   terms are retained. Under no circumstances are the authors responsible for
13   the proper functioning of this software, nor do the authors assume any
14   responsibility for damages incurred with its use.
15
16 Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
17 Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
18 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
19 SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
20 3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
21 RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
22   parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
23 SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
24   based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
25
26 **************************************************************************/
27
28 #warning "ns8390.c is a horrendous mess and needs to be tidied up"
29 #if 0
30
31
32 #include "etherboot.h"
33 #include "nic.h"
34 #include "ns8390.h"
35 #include <gpxe/ethernet.h>
36 #ifdef  INCLUDE_NS8390
37 #include <gpxe/pci.h>
38 #else
39 #include "isa.h"
40 #endif
41
42 static unsigned char    eth_vendor, eth_flags;
43 #ifdef  INCLUDE_WD
44 static unsigned char    eth_laar;
45 #endif
46 static unsigned short   eth_nic_base, eth_asic_base;
47 static unsigned char    eth_memsize, eth_rx_start, eth_tx_start;
48 static Address          eth_bmem, eth_rmem;
49 static unsigned char    eth_drain_receiver;
50
51 #ifdef  INCLUDE_WD
52 static struct wd_board {
53         const char *name;
54         char id;
55         char flags;
56         char memsize;
57 } wd_boards[] = {
58         {"WD8003S",     TYPE_WD8003S,   0,                      MEM_8192},
59         {"WD8003E",     TYPE_WD8003E,   0,                      MEM_8192},
60         {"WD8013EBT",   TYPE_WD8013EBT, FLAG_16BIT,             MEM_16384},
61         {"WD8003W",     TYPE_WD8003W,   0,                      MEM_8192},
62         {"WD8003EB",    TYPE_WD8003EB,  0,                      MEM_8192},
63         {"WD8013W",     TYPE_WD8013W,   FLAG_16BIT,             MEM_16384},
64         {"WD8003EP/WD8013EP",
65                         TYPE_WD8013EP,  0,                      MEM_8192},
66         {"WD8013WC",    TYPE_WD8013WC,  FLAG_16BIT,             MEM_16384},
67         {"WD8013EPC",   TYPE_WD8013EPC, FLAG_16BIT,             MEM_16384},
68         {"SMC8216T",    TYPE_SMC8216T,  FLAG_16BIT | FLAG_790,  MEM_16384},
69         {"SMC8216C",    TYPE_SMC8216C,  FLAG_16BIT | FLAG_790,  MEM_16384},
70         {"SMC8416T",    TYPE_SMC8416T,  FLAG_16BIT | FLAG_790,  MEM_8192},
71         {"SMC8416C/BT", TYPE_SMC8416C,  FLAG_16BIT | FLAG_790,  MEM_8192},
72         {"SMC8013EBP",  TYPE_SMC8013EBP,FLAG_16BIT,             MEM_16384},
73         {NULL,          0,              0,                      0}
74 };
75 #endif
76
77 #ifdef  INCLUDE_3C503
78 static unsigned char    t503_output;    /* AUI or internal xcvr (Thinnet) */
79 #endif
80
81 #if     defined(INCLUDE_WD)
82 #define ASIC_PIO        WD_IAR
83 #define eth_probe       wd_probe
84 #if     defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
85 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
86 #endif
87 #endif
88
89 #if     defined(INCLUDE_3C503)
90 #define eth_probe       t503_probe
91 #if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
92 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
93 #endif
94 #endif
95
96 #if     defined(INCLUDE_NE)
97 #define eth_probe       ne_probe
98 #if     defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
99 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
100 #endif
101 #endif
102
103 #if     defined(INCLUDE_NS8390)
104 #define eth_probe       nepci_probe
105 #if     defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
106 Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
107 #endif
108 #endif
109
110 #if     defined(INCLUDE_3C503)
111 #define ASIC_PIO        _3COM_RFMSB
112 #else
113 #if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
114 #define ASIC_PIO        NE_DATA
115 #endif
116 #endif
117
118 #if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
119 /**************************************************************************
120 ETH_PIO_READ - Read a frame via Programmed I/O
121 **************************************************************************/
122 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
123 {
124 #ifdef  INCLUDE_WD
125         outb(src & 0xff, eth_asic_base + WD_GP2);
126         outb(src >> 8, eth_asic_base + WD_GP2);
127 #else
128         outb(D8390_COMMAND_RD2 |
129                 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
130         outb(cnt, eth_nic_base + D8390_P0_RBCR0);
131         outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
132         outb(src, eth_nic_base + D8390_P0_RSAR0);
133         outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
134         outb(D8390_COMMAND_RD0 |
135                 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
136
137 #ifdef  INCLUDE_3C503
138         outb(src & 0xff, eth_asic_base + _3COM_DALSB);
139         outb(src >> 8, eth_asic_base + _3COM_DAMSB);
140         outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
141 #endif
142 #endif
143
144         if (eth_flags & FLAG_16BIT)
145                 cnt = (cnt + 1) >> 1;
146
147         while(cnt--) {
148 #ifdef  INCLUDE_3C503
149                 while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
150                         ;
151 #endif
152
153                 if (eth_flags & FLAG_16BIT) {
154                         *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
155                         dst += 2;
156                 }
157                 else
158                         *(dst++) = inb(eth_asic_base + ASIC_PIO);
159         }
160
161 #ifdef  INCLUDE_3C503
162         outb(t503_output, eth_asic_base + _3COM_CR);
163 #endif
164 }
165
166 /**************************************************************************
167 ETH_PIO_WRITE - Write a frame via Programmed I/O
168 **************************************************************************/
169 static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
170 {
171 #ifdef  COMPEX_RL2000_FIX
172         unsigned int x;
173 #endif  /* COMPEX_RL2000_FIX */
174 #ifdef  INCLUDE_WD
175         outb(dst & 0xff, eth_asic_base + WD_GP2);
176         outb(dst >> 8, eth_asic_base + WD_GP2);
177 #else
178         outb(D8390_COMMAND_RD2 |
179                 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
180         outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
181         outb(cnt, eth_nic_base + D8390_P0_RBCR0);
182         outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
183         outb(dst, eth_nic_base + D8390_P0_RSAR0);
184         outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
185         outb(D8390_COMMAND_RD1 |
186                 D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
187
188 #ifdef  INCLUDE_3C503
189         outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
190         outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
191
192         outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
193 #endif
194 #endif
195
196         if (eth_flags & FLAG_16BIT)
197                 cnt = (cnt + 1) >> 1;
198
199         while(cnt--)
200         {
201 #ifdef  INCLUDE_3C503
202                 while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
203                         ;
204 #endif
205
206                 if (eth_flags & FLAG_16BIT) {
207                         outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
208                         src += 2;
209                 }
210                 else
211                         outb(*(src++), eth_asic_base + ASIC_PIO);
212         }
213
214 #ifdef  INCLUDE_3C503
215         outb(t503_output, eth_asic_base + _3COM_CR);
216 #else
217 #ifdef  COMPEX_RL2000_FIX
218         for (x = 0;
219                 x < COMPEX_RL2000_TRIES &&
220                 (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
221                 != D8390_ISR_RDC;
222                 ++x);
223         if (x >= COMPEX_RL2000_TRIES)
224                 printf("Warning: Compex RL2000 aborted wait!\n");
225 #endif  /* COMPEX_RL2000_FIX */
226 #ifndef INCLUDE_WD
227         while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
228                 != D8390_ISR_RDC);
229 #endif
230 #endif
231 }
232 #else
233 /**************************************************************************
234 ETH_PIO_READ - Dummy routine when NE2000 not compiled in
235 **************************************************************************/
236 static void eth_pio_read(unsigned int src __unused, unsigned char *dst  __unused, unsigned int cnt __unused) {}
237 #endif
238
239
240 /**************************************************************************
241 enable_multycast - Enable Multicast
242 **************************************************************************/
243 static void enable_multicast(unsigned short eth_nic_base) 
244 {
245         unsigned char mcfilter[8];
246         int i;
247         memset(mcfilter, 0xFF, 8);
248         outb(4, eth_nic_base+D8390_P0_RCR);     
249         outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
250         for(i=0;i<8;i++)
251         {
252                 outb(mcfilter[i], eth_nic_base + 8 + i);
253                 if(inb(eth_nic_base + 8 + i)!=mcfilter[i])
254                         printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i);
255         }
256         outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
257         outb(4 | 0x08, eth_nic_base+D8390_P0_RCR);
258 }
259
260 /**************************************************************************
261 NS8390_RESET - Reset adapter
262 **************************************************************************/
263 static void ns8390_reset(struct nic *nic)
264 {
265         int i;
266
267         eth_drain_receiver = 0;
268 #ifdef  INCLUDE_WD
269         if (eth_flags & FLAG_790)
270                 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
271         else
272 #endif
273                 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
274                         D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
275         if (eth_flags & FLAG_16BIT)
276                 outb(0x49, eth_nic_base+D8390_P0_DCR);
277         else
278                 outb(0x48, eth_nic_base+D8390_P0_DCR);
279         outb(0, eth_nic_base+D8390_P0_RBCR0);
280         outb(0, eth_nic_base+D8390_P0_RBCR1);
281         outb(0x20, eth_nic_base+D8390_P0_RCR);  /* monitor mode */
282         outb(2, eth_nic_base+D8390_P0_TCR);
283         outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
284         outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
285 #ifdef  INCLUDE_WD
286         if (eth_flags & FLAG_790) {
287 #ifdef  WD_790_PIO
288                 outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */
289                 outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */
290 #else
291                 outb(0, eth_nic_base + 0x09);
292 #endif
293         }
294 #endif
295         outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
296         outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
297         outb(0xFF, eth_nic_base+D8390_P0_ISR);
298         outb(0, eth_nic_base+D8390_P0_IMR);
299 #ifdef  INCLUDE_WD
300         if (eth_flags & FLAG_790)
301                 outb(D8390_COMMAND_PS1 |
302                         D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
303         else
304 #endif
305                 outb(D8390_COMMAND_PS1 |
306                         D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
307         for (i=0; i<ETH_ALEN; i++)
308                 outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
309         for (i=0; i<ETH_ALEN; i++)
310                 outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
311         outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
312 #ifdef  INCLUDE_WD
313         if (eth_flags & FLAG_790)
314                 outb(D8390_COMMAND_PS0 |
315                         D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
316         else
317 #endif
318                 outb(D8390_COMMAND_PS0 |
319                         D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
320         outb(0xFF, eth_nic_base+D8390_P0_ISR);
321         outb(0, eth_nic_base+D8390_P0_TCR);     /* transmitter on */
322         outb(4, eth_nic_base+D8390_P0_RCR);     /* allow rx broadcast frames */
323
324         enable_multicast(eth_nic_base);
325
326 #ifdef  INCLUDE_3C503
327         /*
328          * No way to tell whether or not we're supposed to use
329          * the 3Com's transceiver unless the user tells us.
330          * 'flags' should have some compile time default value
331          * which can be changed from the command menu.
332          */
333         t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
334         outb(t503_output, eth_asic_base + _3COM_CR);
335 #endif
336 }
337
338 static int ns8390_poll(struct nic *nic, int retrieve);
339
340 #ifndef INCLUDE_3C503
341 /**************************************************************************
342 ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
343 **************************************************************************/
344 static void eth_rx_overrun(struct nic *nic)
345 {
346         int start_time;
347
348 #ifdef  INCLUDE_WD
349         if (eth_flags & FLAG_790)
350                 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
351         else
352 #endif
353                 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
354                         D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
355
356         /* wait for at least 1.6ms - we wait one timer tick */
357         start_time = currticks();
358         while (currticks() - start_time <= 1)
359                 /* Nothing */;
360
361         outb(0, eth_nic_base+D8390_P0_RBCR0);   /* reset byte counter */
362         outb(0, eth_nic_base+D8390_P0_RBCR1);
363
364         /*
365          * Linux driver checks for interrupted TX here. This is not necessary,
366          * because the transmit routine waits until the frame is sent.
367          */
368
369         /* enter loopback mode and restart NIC */
370         outb(2, eth_nic_base+D8390_P0_TCR);
371 #ifdef  INCLUDE_WD
372         if (eth_flags & FLAG_790)
373                 outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
374         else
375 #endif
376                 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
377                         D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
378
379         /* clear the RX ring, acknowledge overrun interrupt */
380         eth_drain_receiver = 1;
381         while (ns8390_poll(nic, 1))
382                 /* Nothing */;
383         eth_drain_receiver = 0;
384         outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
385
386         /* leave loopback mode - no packets to be resent (see Linux driver) */
387         outb(0, eth_nic_base+D8390_P0_TCR);
388 }
389 #endif  /* INCLUDE_3C503 */
390
391 /**************************************************************************
392 NS8390_TRANSMIT - Transmit a frame
393 **************************************************************************/
394 static void ns8390_transmit(
395         struct nic *nic,
396         const char *d,                  /* Destination */
397         unsigned int t,                 /* Type */
398         unsigned int s,                 /* size */
399         const char *p)                  /* Packet */
400 {
401 #if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
402         Address         eth_vmem = bus_to_virt(eth_bmem);
403 #endif
404 #ifdef  INCLUDE_3C503
405         if (!(eth_flags & FLAG_PIO)) {
406                 memcpy((char *)eth_vmem, d, ETH_ALEN);  /* dst */
407                 memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
408                 *((char *)eth_vmem+12) = t>>8;          /* type */
409                 *((char *)eth_vmem+13) = t;
410                 memcpy((char *)eth_vmem+ETH_HLEN, p, s);
411                 s += ETH_HLEN;
412                 while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
413         }
414 #endif
415
416 #ifdef  INCLUDE_WD
417         if (eth_flags & FLAG_16BIT) {
418                 outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
419                 inb(0x84);
420         }
421 #ifndef WD_790_PIO
422         /* Memory interface */
423         if (eth_flags & FLAG_790) {
424                 outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
425                 inb(0x84);
426         }
427         inb(0x84);
428         memcpy((char *)eth_vmem, d, ETH_ALEN);  /* dst */
429         memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
430         *((char *)eth_vmem+12) = t>>8;          /* type */
431         *((char *)eth_vmem+13) = t;
432         memcpy((char *)eth_vmem+ETH_HLEN, p, s);
433         s += ETH_HLEN;
434         while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
435         if (eth_flags & FLAG_790) {
436                 outb(0, eth_asic_base + WD_MSR);
437                 inb(0x84);
438         }
439 #else
440         inb(0x84);
441 #endif
442 #endif
443
444 #if     defined(INCLUDE_3C503)
445         if (eth_flags & FLAG_PIO)
446 #endif
447 #if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
448         {
449                 /* Programmed I/O */
450                 unsigned short type;
451                 type = (t >> 8) | (t << 8);
452                 eth_pio_write(d, eth_tx_start<<8, ETH_ALEN);
453                 eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
454                 /* bcc generates worse code without (const+const) below */
455                 eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
456                 eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s);
457                 s += ETH_HLEN;
458                 if (s < ETH_ZLEN) s = ETH_ZLEN;
459         }
460 #endif
461 #if     defined(INCLUDE_3C503)
462 #endif
463
464 #ifdef  INCLUDE_WD
465         if (eth_flags & FLAG_16BIT) {
466                 outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
467                 inb(0x84);
468         }
469         if (eth_flags & FLAG_790)
470                 outb(D8390_COMMAND_PS0 |
471                         D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
472         else
473 #endif
474                 outb(D8390_COMMAND_PS0 |
475                         D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
476         outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
477         outb(s, eth_nic_base+D8390_P0_TBCR0);
478         outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
479 #ifdef  INCLUDE_WD
480         if (eth_flags & FLAG_790)
481                 outb(D8390_COMMAND_PS0 |
482                         D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
483         else
484 #endif
485                 outb(D8390_COMMAND_PS0 |
486                         D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
487                         D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
488 }
489
490 /**************************************************************************
491 NS8390_POLL - Wait for a frame
492 **************************************************************************/
493 static int ns8390_poll(struct nic *nic, int retrieve)
494 {
495         int ret = 0;
496         unsigned char rstat, curr, next;
497         unsigned short len, frag;
498         unsigned short pktoff;
499         unsigned char *p;
500         struct ringbuffer pkthdr;
501
502 #ifndef INCLUDE_3C503
503         /* avoid infinite recursion: see eth_rx_overrun() */
504         if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
505                 eth_rx_overrun(nic);
506                 return(0);
507         }
508 #endif  /* INCLUDE_3C503 */
509         rstat = inb(eth_nic_base+D8390_P0_RSR);
510         if (!(rstat & D8390_RSTAT_PRX)) return(0);
511         next = inb(eth_nic_base+D8390_P0_BOUND)+1;
512         if (next >= eth_memsize) next = eth_rx_start;
513         outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
514         curr = inb(eth_nic_base+D8390_P1_CURR);
515         outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
516         if (curr >= eth_memsize) curr=eth_rx_start;
517         if (curr == next) return(0);
518
519         if ( ! retrieve ) return 1;
520
521 #ifdef  INCLUDE_WD
522         if (eth_flags & FLAG_16BIT) {
523                 outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
524                 inb(0x84);
525         }
526 #ifndef WD_790_PIO
527         if (eth_flags & FLAG_790) {
528                 outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
529                 inb(0x84);
530         }
531 #endif
532         inb(0x84);
533 #endif
534         pktoff = next << 8;
535         if (eth_flags & FLAG_PIO)
536                 eth_pio_read(pktoff, (char *)&pkthdr, 4);
537         else
538                 memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
539         pktoff += sizeof(pkthdr);
540         /* incoming length includes FCS so must sub 4 */
541         len = pkthdr.len - 4;
542         if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
543                 || len > ETH_FRAME_LEN) {
544                 printf("Bogus packet, ignoring\n");
545                 return (0);
546         }
547         else {
548                 p = nic->packet;
549                 nic->packetlen = len;           /* available to caller */
550                 frag = (eth_memsize << 8) - pktoff;
551                 if (len > frag) {               /* We have a wrap-around */
552                         /* read first part */
553                         if (eth_flags & FLAG_PIO)
554                                 eth_pio_read(pktoff, p, frag);
555                         else
556                                 memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
557                         pktoff = eth_rx_start << 8;
558                         p += frag;
559                         len -= frag;
560                 }
561                 /* read second part */
562                 if (eth_flags & FLAG_PIO)
563                         eth_pio_read(pktoff, p, len);
564                 else
565                         memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
566                 ret = 1;
567         }
568 #ifdef  INCLUDE_WD
569 #ifndef WD_790_PIO
570         if (eth_flags & FLAG_790) {
571                 outb(0, eth_asic_base + WD_MSR);
572                 inb(0x84);
573         }
574 #endif
575         if (eth_flags & FLAG_16BIT) {
576                 outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
577                 inb(0x84);
578         }
579         inb(0x84);
580 #endif
581         next = pkthdr.next;             /* frame number of next packet */
582         if (next == eth_rx_start)
583                 next = eth_memsize;
584         outb(next-1, eth_nic_base+D8390_P0_BOUND);
585         return(ret);
586 }
587
588 /**************************************************************************
589 NS8390_DISABLE - Turn off adapter
590 **************************************************************************/
591 static void ns8390_disable ( struct nic *nic ) {
592         ns8390_reset(nic);
593 }
594
595 /**************************************************************************
596 NS8390_IRQ - Enable, Disable, or Force interrupts
597 **************************************************************************/
598 static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused)
599 {
600   switch ( action ) {
601   case DISABLE :
602     break;
603   case ENABLE :
604     break;
605   case FORCE :
606     break;
607   }
608 }
609
610 /**************************************************************************
611 ETH_PROBE - Look for an adapter
612 **************************************************************************/
613 #ifdef  INCLUDE_NS8390
614 static int eth_probe (struct dev *dev, struct pci_device *pci)
615 #else
616 static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
617 #endif
618 {
619         struct nic *nic = (struct nic *)dev;
620         int i;
621 #ifdef INCLUDE_NS8390
622         unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
623         unsigned short *probe_addrs = pci_probe_addrs;
624 #endif
625         eth_vendor = VENDOR_NONE;
626         eth_drain_receiver = 0;
627
628         nic->irqno  = 0;
629
630 #ifdef  INCLUDE_WD
631 {
632         /******************************************************************
633         Search for WD/SMC cards
634         ******************************************************************/
635         struct wd_board *brd;
636         unsigned short chksum;
637         unsigned char c;
638         for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
639                 eth_asic_base += 0x20) {
640                 chksum = 0;
641                 for (i=8; i<16; i++)
642                         chksum += inb(eth_asic_base+i);
643                 /* Extra checks to avoid soundcard */
644                 if ((chksum & 0xFF) == 0xFF &&
645                         inb(eth_asic_base+8) != 0xFF &&
646                         inb(eth_asic_base+9) != 0xFF)
647                         break;
648         }
649         if (eth_asic_base > WD_HIGH_BASE)
650                 return (0);
651         /* We've found a board */
652         eth_vendor = VENDOR_WD;
653         eth_nic_base = eth_asic_base + WD_NIC_ADDR;
654
655         nic->ioaddr = eth_nic_base;
656
657         c = inb(eth_asic_base+WD_BID);  /* Get board id */
658         for (brd = wd_boards; brd->name; brd++)
659                 if (brd->id == c) break;
660         if (!brd->name) {
661                 printf("Unknown WD/SMC NIC type %hhX\n", c);
662                 return (0);     /* Unknown type */
663         }
664         eth_flags = brd->flags;
665         eth_memsize = brd->memsize;
666         eth_tx_start = 0;
667         eth_rx_start = D8390_TXBUF_SIZE;
668         if ((c == TYPE_WD8013EP) &&
669                 (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
670                         eth_flags = FLAG_16BIT;
671                         eth_memsize = MEM_16384;
672         }
673         if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
674                 eth_bmem = (0x80000 |
675                  ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
676         } else
677                 eth_bmem = WD_DEFAULT_MEM;
678         if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
679                 /* from Linux driver, 8416BT detects as 8216 sometimes */
680                 unsigned int addr = inb(eth_asic_base + 0xb);
681                 if (((addr >> 4) & 3) == 0) {
682                         brd += 2;
683                         eth_memsize = brd->memsize;
684                 }
685         }
686         outb(0x80, eth_asic_base + WD_MSR);     /* Reset */
687         for (i=0; i<ETH_ALEN; i++) {
688                 nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
689         }
690         DBG ( "\n%s base %4.4x", brd->name, eth_asic_base );
691         if (eth_flags & FLAG_790) {
692 #ifdef  WD_790_PIO
693                 DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) );
694                 eth_bmem = 0;
695                 eth_flags |= FLAG_PIO;          /* force PIO mode */
696                 outb(0, eth_asic_base+WD_MSR);
697 #else
698                 DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
699
700                 outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
701                 outb((inb(eth_asic_base+0x04) |
702                         0x80), eth_asic_base+0x04);
703                 outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
704                         ((unsigned)(eth_bmem >> 11) & 0x40) |
705                         (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
706                 outb((inb(eth_asic_base+0x04) &
707                         ~0x80), eth_asic_base+0x04);
708 #endif
709         } else {
710
711                 DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
712
713                 outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
714         }
715         if (eth_flags & FLAG_16BIT) {
716                 if (eth_flags & FLAG_790) {
717                         eth_laar = inb(eth_asic_base + WD_LAAR);
718                         outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
719                 } else {
720                         outb((eth_laar =
721                                 WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
722 /*
723         The previous line used to be
724                                 WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
725         jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
726         it work for WD8013s.  This seems to work for my 8013 boards. I
727         don't know what is really happening.  I wish I had data sheets
728         or more time to decode the Linux driver. - Ken
729 */
730                 }
731                 inb(0x84);
732         }
733 }
734 #endif
735 #ifdef  INCLUDE_3C503
736 #ifdef  T503_AUI
737         nic->flags = 1;         /* aui */
738 #else
739         nic->flags = 0;         /* no aui */
740 #endif
741         /******************************************************************
742         Search for 3Com 3c503 if no WD/SMC cards
743         ******************************************************************/
744         if (eth_vendor == VENDOR_NONE) {
745                 int     idx;
746                 int     iobase_reg, membase_reg;
747                 static unsigned short   base[] = {
748                         0x300, 0x310, 0x330, 0x350,
749                         0x250, 0x280, 0x2A0, 0x2E0, 0 };
750
751                 /* Loop through possible addresses checking each one */
752
753                 for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
754
755                         eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
756 /*
757  * Note that we use the same settings for both 8 and 16 bit cards:
758  * both have an 8K bank of memory at page 1 while only the 16 bit
759  * cards have a bank at page 0.
760  */
761                         eth_memsize = MEM_16384;
762                         eth_tx_start = 32;
763                         eth_rx_start = 32 + D8390_TXBUF_SIZE;
764
765                 /* Check our base address. iobase and membase should */
766                 /* both have a maximum of 1 bit set or be 0. */
767
768                         iobase_reg = inb(eth_asic_base + _3COM_BCFR);
769                         membase_reg = inb(eth_asic_base + _3COM_PCFR);
770
771                         if ((iobase_reg & (iobase_reg - 1)) ||
772                                 (membase_reg & (membase_reg - 1)))
773                                 continue;               /* nope */
774
775                 /* Now get the shared memory address */
776
777                         eth_flags = 0;
778
779                         switch (membase_reg) {
780                                 case _3COM_PCFR_DC000:
781                                         eth_bmem = 0xdc000;
782                                         break;
783                                 case _3COM_PCFR_D8000:
784                                         eth_bmem = 0xd8000;
785                                         break;
786                                 case _3COM_PCFR_CC000:
787                                         eth_bmem = 0xcc000;
788                                         break;
789                                 case _3COM_PCFR_C8000:
790                                         eth_bmem = 0xc8000;
791                                         break;
792                                 case _3COM_PCFR_PIO:
793                                         eth_flags |= FLAG_PIO;
794                                         eth_bmem = 0;
795                                         break;
796                                 default:
797                                         continue;       /* nope */
798                                 }
799                         break;
800                 }
801
802                 if (base[idx] == 0)             /* not found */
803                         return (0);
804 #ifndef T503_SHMEM
805                 eth_flags |= FLAG_PIO;          /* force PIO mode */
806                 eth_bmem = 0;
807 #endif
808                 eth_vendor = VENDOR_3COM;
809
810
811         /* Need this to make ns8390_poll() happy. */
812
813                 eth_rmem = eth_bmem - 0x2000;
814
815         /* Reset NIC and ASIC */
816
817                 outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
818                 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
819
820         /* Get our ethernet address */
821
822                 outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
823                 nic->ioaddr = eth_nic_base;
824                 DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base );
825                 if (eth_flags & FLAG_PIO)
826                         DBG ( "PIO mode" );
827                 else
828                         DBG ( "memory %4.4x", eth_bmem );
829                 for (i=0; i<ETH_ALEN; i++) {
830                         nic->node_addr[i] = inb(eth_nic_base+i);
831                 }
832                 DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr",
833                       eth_ntoa ( nic->node_addr ) );
834
835                 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
836         /*
837          * Initialize GA configuration register. Set bank and enable shared
838          * mem. We always use bank 1. Disable interrupts.
839          */
840                 outb(_3COM_GACFR_RSEL |
841                         _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
842
843                 outb(0xff, eth_asic_base + _3COM_VPTR2);
844                 outb(0xff, eth_asic_base + _3COM_VPTR1);
845                 outb(0x00, eth_asic_base + _3COM_VPTR0);
846         /*
847          * Clear memory and verify that it worked (we use only 8K)
848          */
849
850                 if (!(eth_flags & FLAG_PIO)) {
851                         memset(bus_to_virt(eth_bmem), 0, 0x2000);
852                         for(i = 0; i < 0x2000; ++i)
853                                 if (*((char *)(bus_to_virt(eth_bmem+i)))) {
854                                         printf ("Failed to clear 3c503 shared mem.\n");
855                                         return (0);
856                                 }
857                 }
858         /*
859          * Initialize GA page/start/stop registers.
860          */
861                 outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
862                 outb(eth_memsize, eth_asic_base + _3COM_PSPR);
863         }
864 #endif
865 #if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
866 {
867         /******************************************************************
868         Search for NE1000/2000 if no WD/SMC or 3com cards
869         ******************************************************************/
870         unsigned char c;
871         if (eth_vendor == VENDOR_NONE) {
872                 char romdata[16], testbuf[32];
873                 int idx;
874                 static char test[] = "NE*000 memory";
875                 static unsigned short base[] = {
876 #ifdef  NE_SCAN
877                         NE_SCAN,
878 #endif
879                         0 };
880                 /* if no addresses supplied, fall back on defaults */
881                 if (probe_addrs == 0 || probe_addrs[0] == 0)
882                         probe_addrs = base;
883                 eth_bmem = 0;           /* No shared memory */
884                 for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
885                         eth_flags = FLAG_PIO;
886                         eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
887                         eth_memsize = MEM_16384;
888                         eth_tx_start = 32;
889                         eth_rx_start = 32 + D8390_TXBUF_SIZE;
890                         c = inb(eth_asic_base + NE_RESET);
891                         outb(c, eth_asic_base + NE_RESET);
892                         inb(0x84);
893                         outb(D8390_COMMAND_STP |
894                                 D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
895                         outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
896                         outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
897                         outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
898                         outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
899 #ifdef  NS8390_FORCE_16BIT
900                         eth_flags |= FLAG_16BIT;        /* force 16-bit mode */
901 #endif
902
903                         eth_pio_write(test, 8192, sizeof(test));
904                         eth_pio_read(8192, testbuf, sizeof(test));
905                         if (!memcmp(test, testbuf, sizeof(test)))
906                                 break;
907                         eth_flags |= FLAG_16BIT;
908                         eth_memsize = MEM_32768;
909                         eth_tx_start = 64;
910                         eth_rx_start = 64 + D8390_TXBUF_SIZE;
911                         outb(D8390_DCR_WTS |
912                                 D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
913                         outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
914                         outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
915                         eth_pio_write(test, 16384, sizeof(test));
916                         eth_pio_read(16384, testbuf, sizeof(test));
917                         if (!memcmp(testbuf, test, sizeof(test)))
918                                 break;
919                 }
920                 if (eth_nic_base == 0)
921                         return (0);
922                 if (eth_nic_base > ISA_MAX_ADDR)        /* PCI probably */
923                         eth_flags |= FLAG_16BIT;
924                 eth_vendor = VENDOR_NOVELL;
925                 eth_pio_read(0, romdata, sizeof(romdata));
926                 for (i=0; i<ETH_ALEN; i++) {
927                         nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
928                 }
929                 nic->ioaddr = eth_nic_base;
930                 DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n",
931                       (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
932                       eth_ntoa ( nic->node_addr ) );
933         }
934 }
935 #endif
936         if (eth_vendor == VENDOR_NONE)
937                 return(0);
938         if (eth_vendor != VENDOR_3COM)
939                 eth_rmem = eth_bmem;
940         ns8390_reset(nic);
941 static struct nic_operations ns8390_operations;
942 static struct nic_operations ns8390_operations = {
943         .connect        = dummy_connect,
944         .poll           = ns8390_poll,
945         .transmit       = ns8390_transmit,
946         .irq            = ns8390_irq,
947         .disable        = ns8390_disable,
948 };
949         nic->nic_op     = &ns8390_operations;
950
951         /* Based on PnP ISA map */
952 #ifdef  INCLUDE_WD
953         dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
954         dev->devid.device_id = htons(0x812a);
955 #endif
956 #ifdef  INCLUDE_3C503
957         dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
958         dev->devid.device_id = htons(0x80f3);
959 #endif
960 #ifdef  INCLUDE_NE
961         dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
962         dev->devid.device_id = htons(0x80d6);
963 #endif
964         return 1;
965 }
966
967 #ifdef  INCLUDE_WD
968 struct isa_driver wd_driver __isa_driver = {
969         .type    = NIC_DRIVER,
970         .name    = "WD",
971         .probe   = wd_probe,
972         .ioaddrs = 0, 
973 };
974 ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
975 #endif
976
977 #ifdef  INCLUDE_3C503
978 struct isa_driver t503_driver __isa_driver = {
979         .type    = NIC_DRIVER,
980         .name    = "3C503",
981         .probe   = t503_probe,
982         .ioaddrs = 0, 
983 };
984 ISA_ROM("3c503","3Com503, Etherlink II[/16]");
985 #endif
986
987 #ifdef  INCLUDE_NE
988 struct isa_driver ne_driver __isa_driver = {
989         .type    = NIC_DRIVER,
990         .name    = "NE*000",
991         .probe   = ne_probe,
992         .ioaddrs = 0, 
993 };
994 ISA_ROM("ne","NE1000/2000 and clones");
995 #endif
996
997 #ifdef  INCLUDE_NS8390
998 static struct pci_device_id nepci_nics[] = {
999 /* A few NE2000 PCI clones, list not exhaustive */
1000 PCI_ROM(0x10ec, 0x8029, "rtl8029",      "Realtek 8029"),
1001 PCI_ROM(0x1186, 0x0300, "dlink-528",    "D-Link DE-528"),
1002 PCI_ROM(0x1050, 0x0940, "winbond940",   "Winbond NE2000-PCI"),          /* Winbond 86C940 / 89C940 */
1003 PCI_ROM(0x1050, 0x5a5a, "winbond940f",  "Winbond W89c940F"),            /* Winbond 89C940F */
1004 PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000"),
1005 PCI_ROM(0x8e2e, 0x3000, "ktiet32p2",    "KTI ET32P2"),
1006 PCI_ROM(0x4a14, 0x5000, "nv5000sc",     "NetVin NV5000SC"),
1007 PCI_ROM(0x12c3, 0x0058, "holtek80232",  "Holtek HT80232"),
1008 PCI_ROM(0x12c3, 0x5598, "holtek80229",  "Holtek HT80229"),
1009 PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34"),
1010 PCI_ROM(0x1106, 0x0926, "via86c926",    "Via 86c926"),
1011 };
1012
1013 PCI_DRIVER ( nepci_driver, "NE2000/PCI", nepci_nics, PCI_NO_CLASS );
1014
1015 BOOT_DRIVER ( "NE2000/PCI", nepci_probe );
1016
1017 #endif /* INCLUDE_NS8390 */
1018
1019 /*
1020  * Local variables:
1021  *  c-basic-offset: 8
1022  * End:
1023  */
1024
1025
1026 #endif