Warnings purge of drivers (continued)
[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 1
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 <gpxe/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( (unsigned char *) 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( (unsigned char *) 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, (unsigned 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 static struct nic_operations ns8390_operations;
611 static struct nic_operations ns8390_operations = {
612         .connect        = dummy_connect,
613         .poll           = ns8390_poll,
614         .transmit       = ns8390_transmit,
615         .irq            = ns8390_irq,
616 };
617
618 /**************************************************************************
619 ETH_PROBE - Look for an adapter
620 **************************************************************************/
621 #ifdef  INCLUDE_NS8390
622 static int eth_probe (struct nic *nic, struct pci_device *pci)
623 #else
624 static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
625 #endif
626 {
627         int i;
628 #ifdef INCLUDE_NS8390
629         unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
630         unsigned short *probe_addrs = pci_probe_addrs;
631 #endif
632         eth_vendor = VENDOR_NONE;
633         eth_drain_receiver = 0;
634
635         nic->irqno  = 0;
636
637 #ifdef  INCLUDE_WD
638 {
639         /******************************************************************
640         Search for WD/SMC cards
641         ******************************************************************/
642         struct wd_board *brd;
643         unsigned short chksum;
644         unsigned char c;
645         for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
646                 eth_asic_base += 0x20) {
647                 chksum = 0;
648                 for (i=8; i<16; i++)
649                         chksum += inb(eth_asic_base+i);
650                 /* Extra checks to avoid soundcard */
651                 if ((chksum & 0xFF) == 0xFF &&
652                         inb(eth_asic_base+8) != 0xFF &&
653                         inb(eth_asic_base+9) != 0xFF)
654                         break;
655         }
656         if (eth_asic_base > WD_HIGH_BASE)
657                 return (0);
658         /* We've found a board */
659         eth_vendor = VENDOR_WD;
660         eth_nic_base = eth_asic_base + WD_NIC_ADDR;
661
662         nic->ioaddr = eth_nic_base;
663
664         c = inb(eth_asic_base+WD_BID);  /* Get board id */
665         for (brd = wd_boards; brd->name; brd++)
666                 if (brd->id == c) break;
667         if (!brd->name) {
668                 printf("Unknown WD/SMC NIC type %hhX\n", c);
669                 return (0);     /* Unknown type */
670         }
671         eth_flags = brd->flags;
672         eth_memsize = brd->memsize;
673         eth_tx_start = 0;
674         eth_rx_start = D8390_TXBUF_SIZE;
675         if ((c == TYPE_WD8013EP) &&
676                 (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
677                         eth_flags = FLAG_16BIT;
678                         eth_memsize = MEM_16384;
679         }
680         if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
681                 eth_bmem = (0x80000 |
682                  ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
683         } else
684                 eth_bmem = WD_DEFAULT_MEM;
685         if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
686                 /* from Linux driver, 8416BT detects as 8216 sometimes */
687                 unsigned int addr = inb(eth_asic_base + 0xb);
688                 if (((addr >> 4) & 3) == 0) {
689                         brd += 2;
690                         eth_memsize = brd->memsize;
691                 }
692         }
693         outb(0x80, eth_asic_base + WD_MSR);     /* Reset */
694         for (i=0; i<ETH_ALEN; i++) {
695                 nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
696         }
697         DBG ( "\n%s base %4.4x", brd->name, eth_asic_base );
698         if (eth_flags & FLAG_790) {
699 #ifdef  WD_790_PIO
700                 DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) );
701                 eth_bmem = 0;
702                 eth_flags |= FLAG_PIO;          /* force PIO mode */
703                 outb(0, eth_asic_base+WD_MSR);
704 #else
705                 DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
706
707                 outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
708                 outb((inb(eth_asic_base+0x04) |
709                         0x80), eth_asic_base+0x04);
710                 outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
711                         ((unsigned)(eth_bmem >> 11) & 0x40) |
712                         (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
713                 outb((inb(eth_asic_base+0x04) &
714                         ~0x80), eth_asic_base+0x04);
715 #endif
716         } else {
717
718                 DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
719
720                 outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
721         }
722         if (eth_flags & FLAG_16BIT) {
723                 if (eth_flags & FLAG_790) {
724                         eth_laar = inb(eth_asic_base + WD_LAAR);
725                         outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
726                 } else {
727                         outb((eth_laar =
728                                 WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
729 /*
730         The previous line used to be
731                                 WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
732         jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
733         it work for WD8013s.  This seems to work for my 8013 boards. I
734         don't know what is really happening.  I wish I had data sheets
735         or more time to decode the Linux driver. - Ken
736 */
737                 }
738                 inb(0x84);
739         }
740 }
741 #endif
742 #ifdef  INCLUDE_3C503
743 #ifdef  T503_AUI
744         nic->flags = 1;         /* aui */
745 #else
746         nic->flags = 0;         /* no aui */
747 #endif
748         /******************************************************************
749         Search for 3Com 3c503 if no WD/SMC cards
750         ******************************************************************/
751         if (eth_vendor == VENDOR_NONE) {
752                 int     idx;
753                 int     iobase_reg, membase_reg;
754                 static unsigned short   base[] = {
755                         0x300, 0x310, 0x330, 0x350,
756                         0x250, 0x280, 0x2A0, 0x2E0, 0 };
757
758                 /* Loop through possible addresses checking each one */
759
760                 for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
761
762                         eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
763 /*
764  * Note that we use the same settings for both 8 and 16 bit cards:
765  * both have an 8K bank of memory at page 1 while only the 16 bit
766  * cards have a bank at page 0.
767  */
768                         eth_memsize = MEM_16384;
769                         eth_tx_start = 32;
770                         eth_rx_start = 32 + D8390_TXBUF_SIZE;
771
772                 /* Check our base address. iobase and membase should */
773                 /* both have a maximum of 1 bit set or be 0. */
774
775                         iobase_reg = inb(eth_asic_base + _3COM_BCFR);
776                         membase_reg = inb(eth_asic_base + _3COM_PCFR);
777
778                         if ((iobase_reg & (iobase_reg - 1)) ||
779                                 (membase_reg & (membase_reg - 1)))
780                                 continue;               /* nope */
781
782                 /* Now get the shared memory address */
783
784                         eth_flags = 0;
785
786                         switch (membase_reg) {
787                                 case _3COM_PCFR_DC000:
788                                         eth_bmem = 0xdc000;
789                                         break;
790                                 case _3COM_PCFR_D8000:
791                                         eth_bmem = 0xd8000;
792                                         break;
793                                 case _3COM_PCFR_CC000:
794                                         eth_bmem = 0xcc000;
795                                         break;
796                                 case _3COM_PCFR_C8000:
797                                         eth_bmem = 0xc8000;
798                                         break;
799                                 case _3COM_PCFR_PIO:
800                                         eth_flags |= FLAG_PIO;
801                                         eth_bmem = 0;
802                                         break;
803                                 default:
804                                         continue;       /* nope */
805                                 }
806                         break;
807                 }
808
809                 if (base[idx] == 0)             /* not found */
810                         return (0);
811 #ifndef T503_SHMEM
812                 eth_flags |= FLAG_PIO;          /* force PIO mode */
813                 eth_bmem = 0;
814 #endif
815                 eth_vendor = VENDOR_3COM;
816
817
818         /* Need this to make ns8390_poll() happy. */
819
820                 eth_rmem = eth_bmem - 0x2000;
821
822         /* Reset NIC and ASIC */
823
824                 outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
825                 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
826
827         /* Get our ethernet address */
828
829                 outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
830                 nic->ioaddr = eth_nic_base;
831                 DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base );
832                 if (eth_flags & FLAG_PIO)
833                         DBG ( "PIO mode" );
834                 else
835                         DBG ( "memory %4.4x", eth_bmem );
836                 for (i=0; i<ETH_ALEN; i++) {
837                         nic->node_addr[i] = inb(eth_nic_base+i);
838                 }
839                 DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr",
840                       eth_ntoa ( nic->node_addr ) );
841
842                 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
843         /*
844          * Initialize GA configuration register. Set bank and enable shared
845          * mem. We always use bank 1. Disable interrupts.
846          */
847                 outb(_3COM_GACFR_RSEL |
848                         _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
849
850                 outb(0xff, eth_asic_base + _3COM_VPTR2);
851                 outb(0xff, eth_asic_base + _3COM_VPTR1);
852                 outb(0x00, eth_asic_base + _3COM_VPTR0);
853         /*
854          * Clear memory and verify that it worked (we use only 8K)
855          */
856
857                 if (!(eth_flags & FLAG_PIO)) {
858                         memset(bus_to_virt(eth_bmem), 0, 0x2000);
859                         for(i = 0; i < 0x2000; ++i)
860                                 if (*((char *)(bus_to_virt(eth_bmem+i)))) {
861                                         printf ("Failed to clear 3c503 shared mem.\n");
862                                         return (0);
863                                 }
864                 }
865         /*
866          * Initialize GA page/start/stop registers.
867          */
868                 outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
869                 outb(eth_memsize, eth_asic_base + _3COM_PSPR);
870         }
871 #endif
872 #if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
873 {
874         /******************************************************************
875         Search for NE1000/2000 if no WD/SMC or 3com cards
876         ******************************************************************/
877         unsigned char c;
878         if (eth_vendor == VENDOR_NONE) {
879                 unsigned char romdata[16];
880                 unsigned char testbuf[32];
881                 int idx;
882                 static unsigned char test[] = "NE*000 memory";
883                 static unsigned short base[] = {
884 #ifdef  NE_SCAN
885                         NE_SCAN,
886 #endif
887                         0 };
888                 /* if no addresses supplied, fall back on defaults */
889                 if (probe_addrs == 0 || probe_addrs[0] == 0)
890                         probe_addrs = base;
891                 eth_bmem = 0;           /* No shared memory */
892                 for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
893                         eth_flags = FLAG_PIO;
894                         eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
895                         eth_memsize = MEM_16384;
896                         eth_tx_start = 32;
897                         eth_rx_start = 32 + D8390_TXBUF_SIZE;
898                         c = inb(eth_asic_base + NE_RESET);
899                         outb(c, eth_asic_base + NE_RESET);
900                         (void) inb(0x84);
901                         outb(D8390_COMMAND_STP |
902                                 D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
903                         outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
904                         outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
905                         outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
906                         outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
907 #ifdef  NS8390_FORCE_16BIT
908                         eth_flags |= FLAG_16BIT;        /* force 16-bit mode */
909 #endif
910
911                         eth_pio_write( (unsigned char *) test, 8192, sizeof(test));
912                         eth_pio_read(8192, testbuf, sizeof(test));
913                         if (!memcmp(test, testbuf, sizeof(test)))
914                                 break;
915                         eth_flags |= FLAG_16BIT;
916                         eth_memsize = MEM_32768;
917                         eth_tx_start = 64;
918                         eth_rx_start = 64 + D8390_TXBUF_SIZE;
919                         outb(D8390_DCR_WTS |
920                                 D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
921                         outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
922                         outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
923                         eth_pio_write( (unsigned char *) test, 16384, sizeof(test));
924                         eth_pio_read(16384, testbuf, sizeof(test));
925                         if (!memcmp(testbuf, test, sizeof(test)))
926                                 break;
927                 }
928                 if (eth_nic_base == 0)
929                         return (0);
930                 if (eth_nic_base > ISA_MAX_ADDR)        /* PCI probably */
931                         eth_flags |= FLAG_16BIT;
932                 eth_vendor = VENDOR_NOVELL;
933                 eth_pio_read(0, romdata, sizeof(romdata));
934                 for (i=0; i<ETH_ALEN; i++) {
935                         nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
936                 }
937                 nic->ioaddr = eth_nic_base;
938                 DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n",
939                       (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
940                       eth_ntoa ( nic->node_addr ) );
941         }
942 }
943 #endif
944         if (eth_vendor == VENDOR_NONE)
945                 return(0);
946         if (eth_vendor != VENDOR_3COM)
947                 eth_rmem = eth_bmem;
948         ns8390_reset(nic);
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, nepci_nics, PCI_NO_CLASS );
1014
1015 DRIVER ( "NE2000/PCI", nic_driver, pci_driver, nepci_driver,
1016          nepci_probe, ns8390_disable );
1017
1018 #endif /* INCLUDE_NS8390 */
1019
1020 /*
1021  * Local variables:
1022  *  c-basic-offset: 8
1023  * End:
1024  */
1025
1026
1027 #endif