]> git.pld-linux.org Git - packages/atlantic.git/blame - atlantic.c
- massive attack s/pld.org.pl/pld-linux.org/
[packages/atlantic.git] / atlantic.c
CommitLineData
402a159c 1/* atlantic.c: Setup program for AT/LANTIC DP83905 ethercards. */
2/*
3 This is a setup and diagnostic program for ISA NE2000 Ethernet adapters.
4 It has specific support for configuring the National Semiconductor
5 AT/LANTIC DP83905 used in on ISA Ethernet adapters such as the NE2000plus.
6 It also works several work-alike chips from other vendors.
7
8 This program must be compiled with '-O'.
9 If you have unresolved references to e.g. inw(), then you haven't used -O.
10 The suggested compile command is at the bottom of this file.
11
12 Copyright 1994-2000 by Donald Becker.
13 This software may be used and distributed according to the terms of
14 the GNU General Public License (GPL), incorporated herein by reference.
15 Contact the author for use under other terms.
16
17 The author may be reached as becker@scyld.com, or C/O
18 Scyld Computing Corporation
19 410 Severn Ave., Suite 210
20 Annapolis MD 21403
21
22 Support and updates are available at
23 http://www.scyld.com/diag/index.html
24
25 Common-sense licensing statement: Using any portion of this program in
26 your own program means that you must give credit to the original author
27 and release the resulting code under the GPL. You must include the
28 text of the license with any redistribution. See
29 http://www.gnu.org/copyleft/gpl.txt
30*/
31#if 0
32static char vcid[] = "$Id$";
33#endif
34
35static char *version_msg =
36"atlantic.c v1.01 7/23/00 Donald Becker http://www.scyld.com/diag/index.html\n";
37static char *usage_msg =
38"Usage: atlantic [-afhNsvVwW] [-p <IOport>] [-F <xcvr-type>] [-P <newIOport>]
39 -p <I/O base address> Use the card at this I/O address (default 0x300).
40 EEPROM configuration commands take effect at the next reset
41 -F 10baseT, 10base2, AUI, 10baset Set the specified transceiver type.
42 -Q 3, 4, 5, 9, 10, 11, 12, 15 Set the IRQ line.
43 -P 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0x360 New I/O base.
44 -N or -W Set to NE2000 or WD8013 clone mode (mutually exclusive)
45";
46
47#if ! defined(__OPTIMIZE__)
48#warning You must compile this program with the correct options!
49#error You must compile this driver with "-O".
50#endif
51#include <unistd.h> /* Hey, we're all POSIX here, right? */
52#include <stdio.h>
53#include <stdlib.h>
54#include <getopt.h>
55#include <string.h>
56#include <errno.h>
57
58#if defined(__linux__) && __GNU_LIBRARY__ == 1
59#include <asm/io.h> /* Newer libraries use <sys/io.h> instead. */
60#else
61#include <sys/io.h>
62#endif
63
64/* Two functions that some GLIBC header file sets omit. grrr... */
65extern int ioperm(unsigned long __base, unsigned long extent, int on_or_off);
66extern int iopl(int level);
67
68struct option longopts[] = {
69 /* { name has_arg *flag val } */
70 {"base-address", 1, 0, 'p'}, /* Base I/O port address. */
71 {"help", 0, 0, 'h'}, /* Give help */
72 {"interface", 0, 0, 'F'}, /* Set the transceiver type (built-in, AUI) */
73 {"NE2000", 1, 0, 'N'}, /* Set to NE2000 mode */
74 {"new_ioport", 1, 0, 'P'}, /* Set a I/O location for the card. */
75 {"irq", 1, 0, 'Q'}, /* Set a new IRQ (interrupt) line. */
76 {"wd8013", 1, 0, 'W'}, /* Set to WD8013 mode */
77 {"verbose", 0, 0, 'v'}, /* Verbose mode */
78 {"version", 0, 0, 'V'}, /* Display version number */
79 {"write-EEPROM", 1, 0, 'w'},/* Write th EEPROMS with the specified vals */
80 { 0, 0, 0, 0 }
81};
82
83/* Three configuration registers are read and may be set from the EEPROM.
84 They are named registers A, B and C
85
86 RegA NE/WD FREAD INT2 INT1 INT0 IOAD2 IOAD1 IOAD0
87 RegB EELOAD BTPR BUSE CHRDY IO16 GDLINK XCVR1 XCVR0
88 RegC SoftEn ClkSel IntMde COMP BtPR3 BtPR2 BtPR1 BtPROM0
89*/
90/* I/O base settings, IOAD2-0, in register A. */
91static int io_base[8] = {
92 0x300, 0x278, 0x240, 0x280, 0x2C0, 0x320, 0x340, 0x360};
93/* The IRQ line settings, INT2-0, in register A, and a reverse map. */
94static int index2irq[8] = {3, 4, 5, 9, 10, 11, 12, 15};
95static int irq2index[16] = {-1, -1, 3, 0, 1, 2, -1, -1,
96 -1, 3, 4, 5, 6, -1, -1, 7};
97/* The transceiver settings, XCVR1-0, in register B.
98 10baseT-LRT is Low Receive Threshold -- "turning the volume up" for long
99 wiring runs.
100*/
101static char *xcvr_name[4] = {"10baseT", "Thinnet", "AUI", "10baseT (LRT)"};
102
103int opt_f = 0;
104
105static void show_config(int regA, int regB);
106static void write_EEPROM(int dp8390_base, int regA, int regB, int regC);
107
108\f
109/*
110 I should say something here... uuhhhhmmm....
111 */
112
113int
114main(int argc, char *argv[])
115{
116 extern char *optarg;
117 int port_base = 0x300; /* Base address of the board. */
118 int ioaddr = 0x300; /* Base address of the 8390 registers. */
119 int new_ioport = -1, new_irq = -1, new_mode = 0;
120 int errflag = 0, verbose = 0, wd_mode = 0, write_eeprom = 0;
121 int show_version = 0, opt_a = 0;
122 int new_io_idx = -1, xcvr = -1; /* I/O port, Transceiver type to set. */
123 int regA, regB, old_regA, old_regB;
124 int option;
125
126 while ((option = getopt(argc, argv, "afF:hi:Q:m:Np:P:vVwW")) != -1)
127 switch (option) {
128 case 'a': opt_a++; break;
129 case 'f': opt_f++; break;
130 case 'F':
131 if (strncmp(optarg, "10base", 6) == 0) {
132 switch (optarg[6]) {
133 case 'T': xcvr = 0; break;
134 case '2': xcvr = 1; break;
135 case '5': xcvr = 2; break;
136 default: errflag++;
137 }
138 } else if (strcmp(optarg, "AUI") == 0)
139 xcvr = 2;
140 else if (optarg[0] >= '0' && optarg[0] <= '3'
141 && optarg[1] == 0)
142 xcvr = optarg[0] - '0';
143 else {
144 fprintf(stderr, "Invalid interface specified: it must be"
145 " 0..3, '10base{T,2,5}' or 'AUI'.\n");
146 errflag++;
147 }
148 break;
149 case 'h': printf(usage_msg); return 0;
150 case 'N': wd_mode = 0; new_mode = 2; break;
151 case 'i':
152 case 'Q':
153 new_irq = atoi(optarg);
154 if (new_irq < 3 || new_irq > 15 || new_irq == 6 || new_irq == 8) {
155 fprintf(stderr, "Invalid new IRQ %#x. Valid values: "
156 "3-5,7,9-15.\n", new_irq);
157 errflag++;
158 }
159 break;
160 case 'p': port_base = strtol(optarg, NULL, 16); break;
161 case 'P': new_ioport = strtol(optarg, NULL, 16); break;
162 case 'v': verbose++; break;
163 case 'V': show_version++; break;
164 case 'w': write_eeprom++; break;
165 case 'W': wd_mode++; new_mode = 1; break;
166 case '?':
167 errflag++;
168 }
169 if (errflag) {
170 fprintf(stderr, usage_msg);
171 return 3;
172 }
173
174 if (verbose || show_version)
175 printf(version_msg);
176
177 /* Turn on access to the I/O ports. */
178 if (ioperm(port_base, 32, 1) < 0) {
179 perror("atlantic: io-perm");
180 fprintf(stderr, " (You must run this program with 'root' permissions.)\n");
181 return 2;
182 }
183
184 /* Check the specified new I/O port value. */
185 if (new_irq >= 0 && (new_irq >= 16 || irq2index[new_irq] < 0)) {
186 fprintf(stderr, "The new IRQ line, %d, is invalid.\n",
187 new_irq);
188 return 3;
189 }
190 if (new_ioport >= 0) {
191 int i;
192 for (i = 0; i < 8; i++)
193 if (new_ioport == io_base[i])
194 break;
195 if (i >= 8) {
196 fprintf(stderr, "The new base I/O address, %#x, is invalid.\n",
197 new_ioport);
198 return 3;
199 }
200 new_io_idx = i;
201 }
202
203 if ( ! opt_f && inb(port_base) == 0xff) {
204 printf("No AT/LANTIC chip found at I/O %#x.\n"
205 " Use '-f' to override if you are certain the chip is at this"
206 " I/O location.\n", port_base);
207 return 1;
208 }
209
210 /* First find if this card is set to WD or NE mode by locating the 8390
211 registers. */
212 {
213 int saved_cmd = inb(port_base);
214 int cntr;
215 outb(0x20, port_base);
216 inb(port_base + 13); /* Clear a counter register */
217 cntr = inb(port_base + 13);
218 if (verbose)
219 printf(" The NE2K 8390 cmd register was %2.2x, cntr %d.\n",
220 saved_cmd, cntr);
221 if (cntr)
222 ioaddr = port_base + 16;
223 else
224 ioaddr = port_base;
225 outb(saved_cmd, port_base);
226 }
227
228 if (opt_a) {
229 int saved_0 = inb(port_base);
230 int window, i;
231
232 printf("8390 registers at %#x (command register was %2.2x)\n",
233 ioaddr, saved_0);
234 for (window = 0; window < 4; window++) {
235 printf(" Window %d:", window);
236 outb((window<<6) | 0x20, ioaddr);
237 for(i = 0; i < 16; i++) {
238 if (window == 0 && i == 6)
239 printf(" **");
240 else
241 printf(" %2.2x", inb(ioaddr + i));
242 }
243 printf(".\n");
244 }
245 if (ioaddr != port_base) { /* WD emulation. */
246 printf("WD8013 compatible registers: ");
247 for(i = 0; i < 16; i++) {
248 printf(" %2.2x", inb(port_base + i));
249 fflush(stdout);
250 }
251 printf(".\n");
252 }
253 }
254
255 printf("Reading the configuration from the AT/LANTIC at %#3x...\n",
256 port_base);
257 outb(0x21, ioaddr); /* Select Window 0 */
258 old_regA = regA = inb(ioaddr + 0x0A);
259 old_regB = regB = inb(ioaddr + 0x0B);
260
261 printf("The current configuration is\n");
262 show_config(regA, regB);
263
264 /* This should never be triggered. We see the card after all!*/
265 if ((regA & 7) == 1)
266 printf(" Your card is set to be configured at boot-time.\n"
267 " Remaining with this software configuration is a bad idea"
268 " when using\n modern systems. The card will likely be"
269 " unintentionally activated at\n unexpected I/O and IRQ"
270 " settings.\n" );
271
272 if (new_mode)
273 regA = (regA & ~0x80) | (new_mode == 1 ? 0x80 : 0);
274 if (new_irq >= 0)
275 regA = (regA & ~0x38) | (irq2index[new_irq]<<3);
276 if (new_io_idx >= 0)
277 regA = (regA & ~0x07) | new_io_idx;
278 if (xcvr >= 0)
279 regB = (regB & 0x5C) | (xcvr & 0x3);
280
281 if (regA != old_regA || regB != old_regB || write_eeprom) {
282 printf("The proposed new configuration is\n");
283 show_config(regA, regB);
284 if ( ! write_eeprom)
285 printf(" Use '-w' to set this as the current configuration "
286 "(valid until next reset).\n"
287 " Use '-w -w' to write the settings to the EEPROM.\n"
288 " Use '-w -w -w' to do both.\n");
289 }
290
291 /* We must write the EEPROM and register B before possibly moving the
292 I/O base. */
293 if (write_eeprom > 1) {
294 printf("Writing the new configuration to the EEPROM...\n");
295 write_EEPROM(ioaddr, regA, regB, 0x30);
296 printf("Wrote the EEPROM at %#3x with 0x%2.2x 0x%2.2x 0x%2.2x.\n",
297 port_base, regA, regB, 0x30);
298 }
299
300 if (write_eeprom & 1) {
301 if (regB != old_regB) {
302 printf(" Setting register B to %#02x.\n", regB);
303 inb(ioaddr + 0x0B);
304 outb(regB, ioaddr + 0x0B);
305 regB = inb(ioaddr + 0x0B);
306 printf(" Register B is now %#02x: Interface %s.\n", regB,
307 xcvr_name[regB & 0x03]);
308 }
309 if (regA != old_regA) {
310 printf(" Setting register A to %#02x (%s mode I/O %#x IRQ %d).\n",
311 regA, regA & 0x80 ? "WD8013" : "NE2000",
312 io_base[regA & 0x07], index2irq[(regA >> 3) & 0x07] );
313 inb(ioaddr + 0x0A);
314 outb(regA, ioaddr + 0x0A);
315 if (port_base == io_base[regA&7]) {
316 ioaddr = port_base + (regA & 0x80 ? 16 : 0);
317 printf(" Register A at base %x is now %#02x.\n",
318 ioaddr, inb(ioaddr + 0x0A));
319 }
320 }
321 }
322
323 return 0;
324}
325
326static void show_config(int regA, int regB)
327{
328 printf(" Register A 0x%2.2x: I/O base @ %#x, IRQ %d,"
329 " %s mode, %s ISA read.\n",
330 regA, io_base[regA & 0x07], index2irq[(regA >> 3) & 0x07],
331 regA & 0x80 ? "WD8013" : "NE2000",
332 regA & 0x40 ? "fast" : "normal" );
333 printf(" Register B 0x%2.2x: Interface %s.\n", regB,
334 xcvr_name[regB & 0x03]);
335 printf(" Boot PROM writes are %sabled, CHRDY after %s%s.\n",
336 regB & 0x40 ? "en" : "dis",
337 regB & 0x10 ? "BALE" : "IORD/IOWR",
338 regB & 0x08 ? ", IO16 after IORD/IOWR" : "");
339 if (regB & 0x20)
340 printf(" Bus error detected.\n");
341}
342
343/* Write the A, B, and C configuration registers into the EEPROM at
344 DP8390_BASE.
345 Ideally this would be done with interrupts disabled, but we do not have
346 that capability with user level code.
347*/
348static void write_EEPROM(int dp8390_base, int regA, int regB, int regC)
349{
350 int ioregb = dp8390_base + 0x0B;
351 int currB = inb(ioregb) & (~0x04) ;
352
353 outb(currB | 0x80, ioregb);
354 inb(ioregb);
355 outb(regA, ioregb);
356 outb(regB, ioregb);
357 outb(regC, ioregb);
358 return;
359}
360\f
361/*
362 * Local variables:
363 * compile-command: "gcc -Wall -Wstrict-prototypes -O6 -o atlantic atlantic.c"
364 * c-indent-level: 4
365 * c-basic-offset: 4
366 * tab-width: 4
367 * End:
368 */
This page took 0.101132 seconds and 4 git commands to generate.