source: bootcd/isolinux/syslinux-6.03/gpxe/src/drivers/net/ne2k_isa.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

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