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