[ne2k_isa] Restore support for ne2k isa cards
[people/sha0/gpxe.git] / src / drivers / net / ne2k_isa.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  Card Detect support adapted from the eCos driver (Christian Plessl <cplessl@ee.ethz.ch>)
19  Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss@gmail.com>
20  **************************************************************************/
21
22 #include "ns8390.h"
23 #include "etherboot.h"
24 #include "nic.h"
25 #include <gpxe/ethernet.h>
26 #include <gpxe/isa.h>
27 #include <errno.h>
28
29 #define ASIC_PIO NE_DATA
30
31 static unsigned char eth_vendor, eth_flags;
32 static unsigned short eth_nic_base, eth_asic_base;
33 static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
34 static Address eth_bmem, eth_rmem;
35 static unsigned char eth_drain_receiver;
36
37 static struct nic_operations ne_operations;
38 static void ne_reset(struct nic *nic, struct isa_device *isa);
39
40 static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, };
41
42 /**************************************************************************
43  ETH_PIO_READ - Read a frame via Programmed I/O
44  **************************************************************************/
45 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {
46         outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
47         outb(cnt, eth_nic_base + D8390_P0_RBCR0);
48         outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
49         outb(src, eth_nic_base + D8390_P0_RSAR0);
50         outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
51         outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
52         if (eth_flags & FLAG_16BIT)
53                 cnt = (cnt + 1) >> 1;
54
55         while (cnt--) {
56                 if (eth_flags & FLAG_16BIT) {
57                         *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO);
58                         dst += 2;
59                 } else
60                         *(dst++) = inb(eth_asic_base + ASIC_PIO);
61         }
62 }
63
64 /**************************************************************************
65  ETH_PIO_WRITE - Write a frame via Programmed I/O
66  **************************************************************************/
67 static void eth_pio_write(const unsigned char *src, unsigned int dst,
68                 unsigned int cnt) {
69         outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
70         outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
71         outb(cnt, eth_nic_base + D8390_P0_RBCR0);
72         outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
73         outb(dst, eth_nic_base + D8390_P0_RSAR0);
74         outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
75         outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
76         if (eth_flags & FLAG_16BIT)
77                 cnt = (cnt + 1) >> 1;
78
79         while (cnt--) {
80
81                 if (eth_flags & FLAG_16BIT) {
82                         outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO);
83                         src += 2;
84                 } else
85                         outb(*(src++), eth_asic_base + ASIC_PIO);
86         }
87 }
88
89 /**************************************************************************
90  enable_multicast - Enable Multicast
91  **************************************************************************/
92 static void enable_multicast(unsigned short eth_nic_base) {
93         unsigned char mcfilter[8];
94         int i;
95
96         memset(mcfilter, 0xFF, 8);
97         outb(4, eth_nic_base + D8390_P0_RCR);
98         outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
99         for (i = 0; i < 8; i++) {
100                 outb(mcfilter[i], eth_nic_base + 8 + i);
101                 if (inb(eth_nic_base + 8 + i) != mcfilter[i])
102                         DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n",
103                                         i);
104         }
105         outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
106         outb(4 | 0x08, eth_nic_base + D8390_P0_RCR);
107 }
108
109 /**************************************************************************
110  NE_PROBE1 - Look for an adapter on the ISA bus
111  **************************************************************************/
112 static int ne_probe1(isa_probe_addr_t ioaddr) {
113         //From the eCos driver
114         unsigned int regd;
115         unsigned int state;
116
117         state = inb(ioaddr);
118         outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP);
119         regd = inb(ioaddr + D8390_P0_TCR);
120
121         if (inb(ioaddr + D8390_P0_TCR)) {
122                 outb(ioaddr, state);
123                 outb(ioaddr + 0x0d, regd);
124                 return 0;
125         }
126
127         return 1;
128 }
129
130 /**************************************************************************
131  NE_PROBE - Initialize an adapter ???
132  **************************************************************************/
133 static int ne_probe(struct nic *nic, struct isa_device *isa) {
134         int i;
135         unsigned char c;
136         unsigned char romdata[16];
137         unsigned char testbuf[32];
138
139         eth_vendor = VENDOR_NONE;
140         eth_drain_receiver = 0;
141
142         nic->irqno = 0;
143         nic->ioaddr = isa->ioaddr;
144         eth_nic_base = isa->ioaddr;
145
146         /******************************************************************
147          Search for NE1000/2000 if no WD/SMC or 3com cards
148          ******************************************************************/
149         if (eth_vendor == VENDOR_NONE) {
150
151                 static unsigned char test[] = "NE*000 memory";
152
153                 eth_bmem = 0; /* No shared memory */
154
155                 eth_flags = FLAG_PIO;
156                 eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
157                 eth_memsize = MEM_16384;
158                 eth_tx_start = 32;
159                 eth_rx_start = 32 + D8390_TXBUF_SIZE;
160                 c = inb(eth_asic_base + NE_RESET);
161                 outb(c, eth_asic_base + NE_RESET);
162                 (void) inb(0x84);
163                 outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base
164                                 + D8390_P0_COMMAND);
165                 outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
166                 outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
167                 outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
168                 outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
169                 eth_pio_write((unsigned char *) test, 8192, sizeof(test));
170                 eth_pio_read(8192, testbuf, sizeof(test));
171                 if (!memcmp(test, testbuf, sizeof(test)))
172                         goto out;
173                 eth_flags |= FLAG_16BIT;
174                 eth_memsize = MEM_32768;
175                 eth_tx_start = 64;
176                 eth_rx_start = 64 + D8390_TXBUF_SIZE;
177                 outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base
178                                 + D8390_P0_DCR);
179                 outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
180                 outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
181                 eth_pio_write((unsigned char *) test, 16384, sizeof(test));
182                 eth_pio_read(16384, testbuf, sizeof(test));
183                 if (!memcmp(testbuf, test, sizeof(test)))
184                         goto out;
185
186
187 out:
188                 if (eth_nic_base == 0)
189                         return (0);
190                 if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
191                         eth_flags |= FLAG_16BIT;
192                 eth_vendor = VENDOR_NOVELL;
193                 eth_pio_read(0, romdata, sizeof(romdata));
194                 for (i = 0; i < ETH_ALEN; i++) {
195                         nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
196                 }
197                 nic->ioaddr = eth_nic_base;
198                 DBG("\nNE%c000 base %4.4x, MAC Addr %s\n",
199                                 (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa(
200                                                 nic->node_addr));
201         }
202
203         if (eth_vendor == VENDOR_NONE)
204                 return (0);
205
206         if (eth_vendor != VENDOR_3COM)
207                 eth_rmem = eth_bmem;
208
209         ne_reset(nic, isa);
210         nic->nic_op = &ne_operations;
211         return 1;
212 }
213
214
215 /**************************************************************************
216  NE_DISABLE - Turn off adapter
217  **************************************************************************/
218 static void ne_disable(struct nic *nic, struct isa_device *isa) {
219         ne_reset(nic, isa);
220 }
221
222
223 /**************************************************************************
224  NE_RESET - Reset adapter
225  **************************************************************************/
226 static void ne_reset(struct nic *nic, struct isa_device *isa __unused)
227 {
228         int i;
229
230         eth_drain_receiver = 0;
231         outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
232                         D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
233         if (eth_flags & FLAG_16BIT)
234         outb(0x49, eth_nic_base+D8390_P0_DCR);
235         else
236         outb(0x48, eth_nic_base+D8390_P0_DCR);
237         outb(0, eth_nic_base+D8390_P0_RBCR0);
238         outb(0, eth_nic_base+D8390_P0_RBCR1);
239         outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
240         outb(2, eth_nic_base+D8390_P0_TCR);
241         outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
242         outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
243
244         outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
245         outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
246         outb(0xFF, eth_nic_base+D8390_P0_ISR);
247         outb(0, eth_nic_base+D8390_P0_IMR);
248         outb(D8390_COMMAND_PS1 |
249                         D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
250
251         for (i=0; i<ETH_ALEN; i++)
252         outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
253         for (i=0; i<ETH_ALEN; i++)
254         outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
255         outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
256         outb(D8390_COMMAND_PS0 |
257                         D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
258         outb(0xFF, eth_nic_base+D8390_P0_ISR);
259         outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
260         outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
261
262         enable_multicast(eth_nic_base);
263 }
264
265
266 /**************************************************************************
267  NE_POLL - Wait for a frame
268  **************************************************************************/
269 static int ne_poll(struct nic *nic __unused, int retrieve __unused)
270 {
271         int ret = 0;
272         unsigned char rstat, curr, next;
273         unsigned short len, frag;
274         unsigned short pktoff;
275         unsigned char *p;
276         struct ringbuffer pkthdr;
277
278         rstat = inb(eth_nic_base+D8390_P0_RSR);
279         if (!(rstat & D8390_RSTAT_PRX)) return(0);
280         next = inb(eth_nic_base+D8390_P0_BOUND)+1;
281         if (next >= eth_memsize) next = eth_rx_start;
282         outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
283         curr = inb(eth_nic_base+D8390_P1_CURR);
284         outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
285         if (curr >= eth_memsize) curr=eth_rx_start;
286         if (curr == next) return(0);
287
288         if ( ! retrieve ) return 1;
289
290         pktoff = next << 8;
291         if (eth_flags & FLAG_PIO)
292         eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
293         else
294         memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
295         pktoff += sizeof(pkthdr);
296         /* incoming length includes FCS so must sub 4 */
297         len = pkthdr.len - 4;
298         if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
299                         || len> ETH_FRAME_LEN) {
300                 DBG("Bogus packet, ignoring\n");
301                 return (0);
302         }
303         else {
304                 p = nic->packet;
305                 nic->packetlen = len; /* available to caller */
306                 frag = (eth_memsize << 8) - pktoff;
307                 if (len> frag) { /* We have a wrap-around */
308                         /* read first part */
309                         if (eth_flags & FLAG_PIO)
310                         eth_pio_read(pktoff, p, frag);
311                         else
312                         memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
313                         pktoff = eth_rx_start << 8;
314                         p += frag;
315                         len -= frag;
316                 }
317                 /* read second part */
318                 if (eth_flags & FLAG_PIO)
319                 eth_pio_read(pktoff, p, len);
320                 else
321                 memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
322                 ret = 1;
323         }
324         next = pkthdr.next; /* frame number of next packet */
325         if (next == eth_rx_start)
326         next = eth_memsize;
327         outb(next-1, eth_nic_base+D8390_P0_BOUND);
328         return(ret);
329 }
330
331
332 /**************************************************************************
333  NE_TRANSMIT - Transmit a frame
334  **************************************************************************/
335 static void ne_transmit(struct nic *nic, const char *d, /* Destination */
336 unsigned int t, /* Type */
337 unsigned int s, /* size */
338 const char *p) { /* Packet */
339
340         /* Programmed I/O */
341         unsigned short type;
342         type = (t >> 8) | (t << 8);
343         eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN);
344         eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN);
345         /* bcc generates worse code without (const+const) below */
346         eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN
347                         + ETH_ALEN), 2);
348         eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s);
349         s += ETH_HLEN;
350         if (s < ETH_ZLEN)
351                 s = ETH_ZLEN;
352
353         outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA,
354                         eth_nic_base + D8390_P0_COMMAND);
355         outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR);
356         outb(s, eth_nic_base + D8390_P0_TBCR0);
357         outb(s >> 8, eth_nic_base + D8390_P0_TBCR1);
358
359         outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2
360                         | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
361 }
362
363 static struct nic_operations ne_operations = { .connect = dummy_connect,
364                 .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq,
365 };
366
367 ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1,
368                 GENERIC_ISAPNP_VENDOR, 0x0600 );
369
370 DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver,
371                 ne_probe, ne_disable );
372
373 ISA_ROM("ne","NE1000/2000 and clones");