~ubuntu-branches/ubuntu/warty/nictools-pci/warty

« back to all changes in this revision

Viewing changes to ne2k-diag.c

  • Committer: Bazaar Package Importer
  • Author(s): Alain Schroeder
  • Date: 2003-06-07 15:49:19 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20030607154919-94glbk5i7db18ve3
Tags: 1.3.6-1
* New Upstream
  * libmii v2.10
    * New chip-ids added
    * Better support for TDK, VIA and Intel chips
  * libflash v2.06
    * Include <sys/io.h> instead of <asm/io.h> on newer glibc to fix
      compile problem on alpha. (Closes: #183512)
  * alta-diag v2.03
    * added online help.
  * eepro100 v2.12
    * more cards known
    * some dokumentation changes
  * myson-diag v1.07
    * added online help
  * natsemi-diag v2.07
    * more error checking
    * support emergency eeprom rewrite
  * ns820-diag v2.04
    * added online help
    * more error checking
  * rtl8139-diag v2.11
    * added online help
    * now more informative
  * tulip-diag v2.17
    * added online help
    * more known cards and flags
  * via-diag v2.09
    * knows about more cards
    * added online help
    * more detailed information
  * vortex-diag v2.14
    * added online help
    * more detailed information
  * winbond-diag v2.01
    * added online help
* Fix compile problems with gcc-3.3 by rewriting multiline
  strings. (Closes: #194996)
* Incorporate all changes from Petter Reinholdtsen <pere@gigs.hungry.com>
  nicely prepared NMU, which never made it out of the delay queue.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  ne2k-diag.c: Diagnostic program for NE2000 ethercards. */
 
2
 
 
3
static const char version_msg[] =
 
4
"ne2k-diag.c:v2.00 4/19/2000 Donald Becker (becker@scyld.com)\n";
 
5
static const char usage_msg[] =
 
6
"\t[Short] [Long arg] [Options]  - [definition]\n"
 
7
"\t-a  --show-registers      - show chip status (-aa for more)\n"
 
8
"\t-D  --debug               - describe program internal state\n"
 
9
"\t-e  --show-eeprom         - show EEPROM contents (-ee for more)\n"
 
10
"\t-p  --base-address 0xNNN  - specify card base address\n"
 
11
"\t-v  --verbose             - verbose mode\n"
 
12
"\t-w  --write               - commit the new values to the EEPROM\n"
 
13
"\t-h  --help                - display this usage message\n"
 
14
"\t-V  --version             - display version\n\n"
 
15
"\t-P  --new-address  0xNNN  - new card base address\n"
 
16
"\t-Q  --new-irq      IRQ    - new card IRQ\n"
 
17
"\t-X  --new-xcvr     N      - new transceiver index.\n"
 
18
;
 
19
 
 
20
/*
 
21
        Written 1993,1994,1999,2000 by Donald Becker.
 
22
        Copyright 1994,1999-2000 Donald Becker
 
23
        Copyright 1993 United States Government as represented by the
 
24
        Director, National Security Agency.
 
25
 
 
26
        This software may be used and distributed according to the terms of
 
27
        the GNU General Public License (GPL), incorporated herein by reference.
 
28
         http://scyld.com/expert/license.html
 
29
        No substitution of license terms are permitted.
 
30
 
 
31
        The author may be reached as becker@scyld.com, or C/O
 
32
         Scyld Computing Corporation
 
33
         410 Severn Ave., Suite 210
 
34
         Annapolis MD 21403
 
35
 
 
36
        This program is used to diagnose detection ("probe") problems with NE1000
 
37
        NE2000 work-alike cards.   The probe routine is very similar to that
 
38
        used in the Linux NE2000 driver, and should work with any NE2000
 
39
        clone.
 
40
 
 
41
        See the bottom of this file for the compile command.
 
42
        Do not forget the "-O"!
 
43
 
 
44
        Some of the names and comments for the #defines came from Crynwr.
 
45
 
 
46
        1999/Mar/18 James Bourne <jbourne@affinity-systems.ab.ca>
 
47
        Fixed -h --help and -V --version flags
 
48
        References
 
49
      RTL8019 datasheet, http://www.realtek.com.tw/cn/cn.html
 
50
*/
 
51
 
 
52
#ifndef __OPTIMIZE__
 
53
#warning  You must compile this program with the correct options!
 
54
#warning  See the last lines of the source file for the suggested command.
 
55
#error You must compile this driver with "-O".
 
56
#endif
 
57
 
 
58
#include <unistd.h>
 
59
#include <stdio.h>
 
60
#include <stdlib.h>
 
61
#include <getopt.h>
 
62
 
 
63
#if defined(__linux__)  &&  __GNU_LIBRARY__ == 1
 
64
#include <asm/io.h>
 
65
#else
 
66
#include <sys/io.h>
 
67
#endif
 
68
 
 
69
 
 
70
 
 
71
#define printk printf
 
72
 
 
73
#define NS_CMD   (dev->base_addr)
 
74
#define NS_BASE  (dev->base_addr)
 
75
#define NS_DATAPORT             0x10    /* NatSemi-defined port window offset. */
 
76
#define NE_DATAPORT             0x10    /* NatSemi-defined port window offset. */
 
77
#define NS_RESET                0x1f    /* Issue a read to reset, a write to clear. */
 
78
 
 
79
#define NE1SM_START_PG  0x20    /* First page of TX buffer */
 
80
#define NE1SM_STOP_PG   0x40    /* Last page +1 of RX ring */
 
81
#define NESM_START_PG   0x40    /* First page of TX buffer */
 
82
#define NESM_STOP_PG    0x80    /* Last page +1 of RX ring */
 
83
 
 
84
#define E8390_CMD               0x00    /* The command register (for all pages) */
 
85
#define E8390_STOP              0x01    /* Stop and reset the chip */
 
86
#define E8390_START             0x02    /* Start the chip, clear reset */
 
87
#define E8390_RREAD             0x08    /* Remote read */
 
88
#define E8390_NODMA             0x20    /* Remote DMA */
 
89
#define E8390_PAGE0             0x00    /* Select page chip registers */
 
90
#define E8390_PAGE1             0x40    /* using the two high-order bits */
 
91
#define E8390_PAGE2             0x80
 
92
#define E8390_PAGE3             0xC0    /* Page 3 is invalid on the real 8390. */
 
93
 
 
94
#define E8390_RXOFF 0x20                /* EN0_RXCR: Accept no packets */
 
95
#define E8390_TXOFF 0x02                /* EN0_TXCR: Transmitter off */
 
96
 
 
97
/* Page 0 register offsets. */
 
98
#define EN0_CLDALO              0x01    /* Low byte of current local dma addr  RD */
 
99
#define EN0_STARTPG             0x01    /* Starting page of ring bfr WR */
 
100
#define EN0_CLDAHI              0x02    /* High byte of current local dma addr  RD */
 
101
#define EN0_STOPPG              0x02    /* Ending page +1 of ring bfr WR */
 
102
#define EN0_BOUNDARY    0x03    /* Boundary page of ring bfr RD WR */
 
103
#define EN0_TSR                 0x04    /* Transmit status reg RD */
 
104
#define EN0_TPSR                0x04    /* Transmit starting page WR */
 
105
#define EN0_NCR                 0x05    /* Number of collision reg RD */
 
106
#define EN0_TCNTLO              0x05    /* Low  byte of tx byte count WR */
 
107
#define EN0_FIFO                0x06    /* FIFO RD */
 
108
#define EN0_TCNTHI              0x06    /* High byte of tx byte count WR */
 
109
#define EN0_ISR                 0x07    /* Interrupt status reg RD WR */
 
110
#define EN0_CRDALO              0x08    /* low byte of current remote dma address RD */
 
111
#define EN0_RSARLO              0x08    /* Remote start address reg 0 */
 
112
#define EN0_CRDAHI              0x09    /* high byte, current remote dma address RD */
 
113
#define EN0_RSARHI              0x09    /* Remote start address reg 1 */
 
114
#define EN0_RCNTLO              0x0a    /* Remote byte count reg WR */
 
115
#define EN0_RCNTHI              0x0b    /* Remote byte count reg WR */
 
116
#define EN0_RSR                 0x0c    /* rx status reg RD */
 
117
#define EN0_RXCR                0x0c    /* RX configuration reg WR */
 
118
#define EN0_TXCR                0x0d    /* TX configuration reg WR */
 
119
#define EN0_COUNTER0    0x0d    /* Rcv alignment error counter RD */
 
120
#define EN0_DCFG                0x0e    /* Data configuration reg WR */
 
121
#define EN0_COUNTER1    0x0e    /* Rcv CRC error counter RD */
 
122
#define EN0_IMR                 0x0f    /* Interrupt mask reg WR */
 
123
#define EN0_COUNTER2    0x0f    /* Rcv missed frame error counter RD */
 
124
 
 
125
 
 
126
void write_EEPROM(int port_base, int regA, int regB, int regC);
 
127
static int do_probe(long ioaddr);
 
128
static void rtl8019(long ioaddr);
 
129
 
 
130
int opt_a = 0, debug = 0, show_eeprom = 0, opt_F = 0, new_irq = 0;
 
131
int new_port_base = 0;
 
132
int interface = -1;
 
133
int do_write_eeprom = 0;
 
134
 
 
135
struct option longopts[] = {
 
136
 /* { name      has_arg  *flag  val } */
 
137
        {"show-registers",      0, 0, 'a'},
 
138
        {"debug",                       0, 0, 'D'},
 
139
        {"show-eeprom",         0, 0, 'e'},
 
140
        {"base-address",        1, 0, 'p'}, /* Base address */
 
141
        {"help",                        0, 0, 'h'},     /* Give help */
 
142
        {"verbose",                     0, 0, 'v'},     /* Verbose mode */
 
143
        {"version",                     0, 0, 'V'},     /* Display version number */
 
144
        {"interface",           1, 0, 'F'},     /* New transceiver index (10baseT, AUI) */
 
145
        {"new-address",         1, 0, 'P'}, /* Base address */
 
146
        {"new-irq",                     1, 0, 'Q'},     /* New interrupt number */
 
147
        { 0,                                    0, 0, 0 }
 
148
};
 
149
 
 
150
 
 
151
/*      Probe for various non-shared-memory ethercards.
 
152
 
 
153
   NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
 
154
   buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
 
155
   the SAPROM, while other supposed NE2000 clones must be detected by their
 
156
   SA prefix.
 
157
 
 
158
   Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
 
159
   mode results in doubled values, which can be detected and compensated for.
 
160
 
 
161
   The probe is also responsible for initializing the card and filling
 
162
   in the 'dev' and 'ei_status' structures.
 
163
 
 
164
   We use the minimum memory size for some ethercard product lines, iff we can't
 
165
   distinguish models.  You can increase the packet buffer size by setting
 
166
   PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
 
167
                E1010   starts at 0x100 and ends at 0x2000.
 
168
                E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
 
169
                E2010   starts at 0x100 and ends at 0x4000.
 
170
                E2010-x starts at 0x100 and ends at 0xffff.      */
 
171
 
 
172
static void usage(char *prog)
 
173
{
 
174
        fprintf(stderr, "%s: %s", prog, version_msg);
 
175
        fprintf(stderr, "Usage: %s [-p 0xNNN] [-i IRQ] [-f N] [-v] [-h] [-V]\n",
 
176
                        prog);
 
177
        fprintf(stderr, usage_msg);
 
178
}
 
179
 
 
180
int main(int argc, char *argv[])
 
181
{
 
182
        int show_version = 0, errflag = 0;
 
183
        int port_base = 0x300;
 
184
        int verbose = 0;
 
185
        int c;
 
186
        extern char *optarg;
 
187
        int option_index = 0;
 
188
 
 
189
        while ((c = getopt_long(argc,argv, "aDeF:i:p:P:Q:svwX:Vh",
 
190
                                                        longopts, &option_index))
 
191
                != -1) {
 
192
                switch (c) {
 
193
                case 'a': opt_a++; break;
 
194
                case 'D': debug++; break;
 
195
                case 'e': show_eeprom++; break;
 
196
                case 'F':
 
197
                case 'X': opt_F++; interface = atoi(optarg); break;
 
198
                case 'p': port_base = strtol(optarg, NULL, 16); break;
 
199
                case 'P': new_port_base = strtol(optarg, NULL, 16); break;
 
200
                case 'Q':
 
201
                        new_irq = atoi(optarg);
 
202
                        /* On ISA IRQ2 == IRQ9, with IRQ9 the proper name. */
 
203
                        if (new_irq < 2 || new_irq > 15 || new_irq == 6 || new_irq == 8) {
 
204
                                fprintf(stderr, "Invalid new IRQ %#x.  Valid values: "
 
205
                                                "3-5,7,9-15.\n", new_irq);
 
206
                                errflag++;
 
207
                        }
 
208
                        break;
 
209
                case 'v': verbose++;     break;
 
210
                case 'V': show_version++;                break;
 
211
                case 'w': do_write_eeprom++;    break;
 
212
                case '?':
 
213
                case 'h':
 
214
                        errflag++; break;
 
215
                }
 
216
        }
 
217
        if (errflag) {
 
218
                fprintf(stderr, usage_msg);
 
219
                return 3;
 
220
        }
 
221
 
 
222
        if (verbose || show_version)
 
223
                printf(version_msg);
 
224
 
 
225
        if (ioperm(port_base, 32, 1)) {
 
226
                perror("ne2k-diag: ioperm()");
 
227
                fprintf(stderr, "This program must be run as root.\n");
 
228
                return 2;
 
229
        }
 
230
        /* The following is needed for SLOW_DOWN_IO. */
 
231
        if (ioperm(0x80, 1, 1)) {
 
232
                perror("ioperm");
 
233
                return 1;
 
234
        }
 
235
 
 
236
        printf("Checking the ethercard at %#3x.\n", port_base);
 
237
        {       int regd;
 
238
                long ioaddr = port_base;
 
239
 
 
240
                outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
 
241
                regd = inb_p(ioaddr + 0x0d);
 
242
                printk("  Receive alignment error counter (%#x) is %2.2x\n",
 
243
                           ioaddr + 0x0d, regd);
 
244
                outb_p(0xff, ioaddr + 0x0d);
 
245
                outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
 
246
                inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
 
247
                if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
 
248
                        outb(regd, ioaddr + 0x0d);      /* Restore the old values. */
 
249
                        printk("  Failed initial NE2000 probe, value %2.2x.\n",
 
250
                                   inb(ioaddr + EN0_COUNTER0));
 
251
                } else
 
252
                        printk("  Passed initial NE2000 probe, value %2.2x.\n",
 
253
                                   inb(ioaddr + EN0_COUNTER0));
 
254
 
 
255
        }
 
256
 
 
257
        do_probe(port_base);
 
258
        return 0;
 
259
}
 
260
 
 
261
static int do_probe(long ioaddr)
 
262
{
 
263
        int i;
 
264
        int neX000, ctron, dlink;
 
265
        unsigned char SA_prom[32];
 
266
        int wordlength = 2;
 
267
        char *name;
 
268
        int start_page, stop_page;
 
269
 
 
270
        struct {char value, offset; } program_seq[] = {
 
271
                {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
 
272
                {0x48,  EN0_DCFG},              /* Set byte-wide (0x48) access. */
 
273
                {0x00,  EN0_RCNTLO},    /* Clear the count regs. */
 
274
                {0x00,  EN0_RCNTHI},
 
275
                {0x00,  EN0_IMR},               /* Mask completion irq. */
 
276
                {0xFF,  EN0_ISR},
 
277
                {E8390_RXOFF, EN0_RXCR},                /* 0x20  Set to monitor */
 
278
                {E8390_TXOFF, EN0_TXCR},                /* 0x02  and loopback mode. */
 
279
                {32,                    EN0_RCNTLO},
 
280
                {0x00,  EN0_RCNTHI},
 
281
                {0x00,  EN0_RSARLO},    /* DMA starting at 0x0000. */
 
282
                {0x00,  EN0_RSARHI},
 
283
                {E8390_RREAD+E8390_START, E8390_CMD},
 
284
        };
 
285
 
 
286
        /* Read the 16 bytes of station address prom, returning 1 for
 
287
           an eight-bit interface and 2 for a 16-bit interface.
 
288
           We must first initialize registers, similar to NS8390_init(eifdev, 0).
 
289
           We can't reliably read the SAPROM address without this.
 
290
           (I learned the hard way!). */
 
291
        for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
 
292
                outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
 
293
 
 
294
        for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
 
295
                SA_prom[i] = inb_p(ioaddr + NE_DATAPORT);
 
296
                SA_prom[i+1] = inb_p(ioaddr + NE_DATAPORT);
 
297
                if (SA_prom[i] != SA_prom[i+1])
 
298
                        wordlength = 1;
 
299
        }
 
300
 
 
301
        printk("Station Address PROM    0:");
 
302
        for(i = 0; i < sizeof(SA_prom)/2; i++)
 
303
                printk(" %2.2x", SA_prom[i]);
 
304
        printk("\nStation Address PROM %#2x:", i);
 
305
        for(; i < sizeof(SA_prom); i++)
 
306
                printk(" %2.2x", SA_prom[i]);
 
307
        printk("\n");
 
308
 
 
309
        if (wordlength == 2) {
 
310
                /* We must set the 8390 for word mode, AND RESET IT. */
 
311
                int tmp;
 
312
                outb_p(0x49, ioaddr + EN0_DCFG);
 
313
                tmp = inb_p(ioaddr + NS_RESET);
 
314
                outb(tmp, ioaddr + NS_RESET);
 
315
                /* Un-double the SA_prom values. */
 
316
                for (i = 0; i < 16; i++)
 
317
                        SA_prom[i] = SA_prom[i+i];
 
318
        }
 
319
 
 
320
        neX000 =  (SA_prom[14] == 0x57  &&      SA_prom[15] == 0x57);
 
321
        ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
 
322
        dlink =  (SA_prom[0] == 0x00 && SA_prom[1] == 0xDE && SA_prom[2] == 0x01);
 
323
 
 
324
        /* Set up the rest of the parameters. */
 
325
        if (neX000 || dlink) {
 
326
                if (wordlength == 2) {
 
327
                        name = dlink ? "DE200" : "NE2000";
 
328
                        start_page = NESM_START_PG;
 
329
                        stop_page = NESM_STOP_PG;
 
330
                } else {
 
331
                        name = dlink ? "DE100" : "D-Link";
 
332
                        start_page = NE1SM_START_PG;
 
333
                        stop_page = NE1SM_STOP_PG;
 
334
                }
 
335
        } else if (ctron) {
 
336
                name = "Cabletron";
 
337
                start_page = 0x01;
 
338
                stop_page = (wordlength == 2) ? 0x40 : 0x20;
 
339
        } else {
 
340
                printk(" Invalid signature found, wordlength %d.\n", wordlength);
 
341
                return 1;
 
342
        }
 
343
 
 
344
        printk("  %s found at %#x, using start page %#x and end page %#x.\n",
 
345
                   name, ioaddr, start_page, stop_page);
 
346
 
 
347
        outb_p(E8390_NODMA + E8390_PAGE1, ioaddr + E8390_CMD);
 
348
        printf("The current MAC stations address is ");
 
349
        for (i = 1; i < 6; i++)
 
350
                printf("%2.2X:", inb(ioaddr + i));
 
351
        printf("%2.2X.\n", inb(ioaddr + i));
 
352
        
 
353
        if (opt_a) {
 
354
                int page; 
 
355
                for (page = 0; page < 4; page++) {
 
356
                        printf("8390 page %d:", page);
 
357
                        outb_p(E8390_NODMA + (page << 6), ioaddr + E8390_CMD);
 
358
                        for(i = 0; i < 16; i++)
 
359
                                printf(" %2.2x", inb_p(ioaddr + i));
 
360
                        printf(".\n");
 
361
                }
 
362
        }
 
363
 
 
364
        outb_p(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
 
365
        /* Check for a RealTek 8019 chip. */
 
366
        if (inb(ioaddr + 10) == 'P'  &&  inb(ioaddr + 11) == 'p')
 
367
                rtl8019(ioaddr);
 
368
 
 
369
        return 0;
 
370
}
 
371
 
 
372
/* Serial EEPROM section. */
 
373
/* The description of EEPROM access. */
 
374
struct ee_ctrl_bits {
 
375
        int offset;
 
376
        unsigned char shift_clk,        /* Bit that drives SK (shift clock) pin */
 
377
                read_bit,                               /* Mask bit for DO pin value */
 
378
                write_0, write_1,               /* Enable chip and drive DI pin with 0 / 1 */
 
379
                disable;                                /* Disable chip. */
 
380
};
 
381
 
 
382
/* The EEPROM commands include the alway-set leading bit. */
 
383
enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, };
 
384
 
 
385
/* This executes a generic EEPROM command, typically a write or write enable.
 
386
   It returns the data output from the EEPROM, and thus may also be used for
 
387
   reads and EEPROM sizing. */
 
388
static int do_eeprom_cmd(struct ee_ctrl_bits *ee, long ioaddr, int cmd,
 
389
                                                 int cmd_len)
 
390
{
 
391
        long ee_addr = ioaddr + ee->offset;
 
392
        unsigned retval = 0;
 
393
 
 
394
        if (debug > 1)
 
395
                printf(" EEPROM op 0x%x: ", cmd);
 
396
 
 
397
        /* Shift the command bits out. */
 
398
        do {
 
399
                short dataval = (cmd & (1 << cmd_len)) ? ee->write_1 : ee->write_0;
 
400
                outb(dataval, ee_addr);
 
401
                if (debug > 2)
 
402
                        printf("%X", inb(ee_addr) & 15);
 
403
                outb(dataval |ee->shift_clk, ee_addr);
 
404
                retval = (retval << 1) | ((inb(ee_addr) & ee->read_bit) ? 1 : 0);
 
405
        } while (--cmd_len >= 0);
 
406
        outb(ee->write_0, ee_addr);
 
407
 
 
408
        /* Terminate the EEPROM access. */
 
409
        outb(ee->disable, ee_addr);
 
410
        if (debug > 1)
 
411
                printf(" EEPROM result is 0x%5.5x.\n", retval);
 
412
        return retval;
 
413
}
 
414
 
 
415
/* Wait for the EEPROM to finish what it is doing. */
 
416
static int eeprom_busy_poll(struct ee_ctrl_bits *ee, long ioaddr)
 
417
{
 
418
        int ee_addr = ioaddr + ee->offset;
 
419
        int i;
 
420
 
 
421
        outb(ee->write_0, ee_addr);
 
422
        for (i = 0; i < 10000; i++)                     /* Typical 2000 ticks */
 
423
                if (inb(ee_addr) & ee->read_bit)
 
424
                        break;
 
425
        return i;
 
426
}
 
427
 
 
428
/* The abstracted functions for EEPROM access. */
 
429
static int read_eeprom(struct ee_ctrl_bits *ee, long ioaddr, int location)
 
430
{
 
431
        int addr_len = 6;
 
432
        return do_eeprom_cmd(ee, ioaddr, ((EE_ReadCmd << addr_len) | location) << 16,
 
433
                                                 3 + addr_len + 16) & 0xffff;
 
434
}
 
435
 
 
436
static void write_eeprom(struct ee_ctrl_bits *eebits, long ioaddr, int index,
 
437
                                                 int value)
 
438
{
 
439
        int addr_len = 6;
 
440
        int i;
 
441
 
 
442
        /* Poll for previous op finished. */
 
443
        eeprom_busy_poll(eebits, ioaddr);
 
444
 
 
445
        /* Enable programming modes. */
 
446
        do_eeprom_cmd(eebits, ioaddr, (0x4f << (addr_len-4)), 3 + addr_len);
 
447
        /* Do the actual write. */
 
448
        do_eeprom_cmd(eebits, ioaddr,
 
449
                                  (((EE_WriteCmd<<addr_len) | index)<<16) | (value & 0xffff),
 
450
                                  3 + addr_len + 16);
 
451
        i = eeprom_busy_poll(eebits, ioaddr);
 
452
        if (debug)
 
453
                printf(" Write finished after %d ticks.\n", i);
 
454
        /* Disable programming.  Note: this command is not instantaneous, but
 
455
           we check for busy before the next write. */
 
456
        do_eeprom_cmd(eebits, ioaddr, (0x40 << (addr_len-4)), 3 + addr_len);
 
457
}
 
458
 
 
459
 
 
460
 
 
461
/* The RealTek RTL8019 specific routines. */
 
462
static const char irqmap[] = { 9, 3, 4, 5, 10, 11, 12, 15 };
 
463
static const char irq2config_map[16] = {
 
464
        -1,-1,0x00,0x10,  0x20,0x30,-1,-1,  -1,0x00,0x40,0x50, 0x60,-1,-1,0x70};
 
465
static const int iomap[] = {
 
466
        0x300, 0x320, 0x340, 0x360,  0x380, 0x3A0, 0x3C0, 0x3E0,
 
467
        0x200, 0x220, 0x240, 0x260,  0x280, 0x2A0, 0x2C0, 0x2E0 };
 
468
static const char *const xcvr_modes[4] = {
 
469
        "10baseT or coax, selected on 10baseT link beat",
 
470
        "10baseT with link test disabled", "10base5 / AUI", "10base2"};
 
471
struct ee_ctrl_bits rtl_ee_tbl = {0x01,  0x04, 0x01, 0x88, 0x8A, 0x00 };
 
472
#define EEPROM_SIZE 64
 
473
 
 
474
static void rtl8019(long ioaddr)
 
475
{
 
476
        int config0, config1, config2, config3, eeword0, eeword1;
 
477
        int i;
 
478
 
 
479
        /* The rtl8019-specific registers are on page 3. */  
 
480
        outb(E8390_NODMA+E8390_PAGE3, ioaddr + E8390_CMD);
 
481
        /* We do not use symbolic names for the Realtek-specific registers. */
 
482
        config0 = inb(ioaddr + 3);
 
483
        config1 = inb(ioaddr + 4);
 
484
        config2 = inb(ioaddr + 5);
 
485
        config3 = inb(ioaddr + 6);
 
486
        printf("This is a RTL8019%s chip in jumper%s%s mode.\n",
 
487
                   config0 & 0xC0 ? "" : "AS", config0 & 0x08 ? "ed" : "less",
 
488
                   (config0 & 0x08) == 0 && (config3 & 0x80) ? " PnP" :"");
 
489
        printf("  The current settings are: IRQ %d (%sabled, I/O address 0x%x,\n",
 
490
                   irqmap[(config1>>4) & 7], config1 & 0x80 ? "en" : "dis",
 
491
                   iomap[config1 & 15]);
 
492
        printf("     The transceiver is set to %s,\n"
 
493
                   "     The chip is set to %s duplex.\n",
 
494
                   xcvr_modes[config2 >> 6], config3 & 0x40 ? "full" : "half");
 
495
        eeword0 = read_eeprom(&rtl_ee_tbl, ioaddr, 0);
 
496
        eeword1 = read_eeprom(&rtl_ee_tbl, ioaddr, 1);
 
497
        config1 = eeword0;
 
498
        config2 = eeword0 >> 8;
 
499
        config3 = eeword1;
 
500
        printf("  The EEPROM settings are: IRQ %d, I/O address 0x%x, %sPnP mode.\n"
 
501
                   "     The transceiver is set to %s,\n"
 
502
                   "     The chip is set to %s duplex.\n",
 
503
                   irqmap[(config1>>4) & 7], iomap[config1 & 15],
 
504
                   (config3 & 0x80) ? "" :"non-",
 
505
                   xcvr_modes[config2 >> 6], config3 & 0x40 ? "full" : "half");
 
506
        if (show_eeprom) {
 
507
                unsigned short sum = 0, val;
 
508
                int i;
 
509
                printf("EEPROM contents:");
 
510
                for (i = 0; i < EEPROM_SIZE; i++) {
 
511
                        val = read_eeprom(&rtl_ee_tbl, ioaddr, i);
 
512
                        printf("%s %4.4x", (i & 7) == 0 ? "\n ":"", val);
 
513
                        sum += val;
 
514
                }
 
515
                printf("\n The word-wide EEPROM checksum is %#4.4x.\n", sum);
 
516
        }
 
517
        if (opt_F  ||  new_irq > 0  ||  new_port_base > 0) {
 
518
                int newval0 = eeword0;
 
519
                if (opt_F  &&  interface >= 0  &&  interface < 4) {
 
520
                        newval0 &= 0x3fff;
 
521
                        newval0 |= interface << 14;
 
522
                }
 
523
                if (new_irq > 0 && new_irq < 16 && irq2config_map[new_irq] > 0) {
 
524
                        newval0 &= 0xff8f;
 
525
                        newval0 |= irq2config_map[new_irq];
 
526
                }
 
527
 
 
528
                for (i = 0; i < 16; i++)
 
529
                        if (iomap[i] == new_port_base) {
 
530
                                newval0 &= 0xfff0;
 
531
                                newval0 |= i;
 
532
                                break;
 
533
                        }
 
534
                if (do_write_eeprom) {
 
535
                        printf(" Writing 0x%4.4x to EEPROM word 0.\n", newval0);
 
536
                        write_eeprom(&rtl_ee_tbl, ioaddr, 0, newval0);
 
537
                } else
 
538
                        printf(" Would write 0x%4.4x to EEPROM word 0 with '-w'.\n",
 
539
                                   newval0);
 
540
        }
 
541
}
 
542
 
 
543
/*
 
544
 * Local variables:
 
545
 *  compile-command: "gcc -Wall -O6 -o ne2k-diag ne2k-diag.c"
 
546
 *  tab-width: 4
 
547
 *  c-indent-level: 4
 
548
 *  c-basic-offset: 4
 
549
 * End:
 
550
 */