56e307f86a7d3a428d599b6ad1598609 atlantic.c
authorankry <ankry@pld-linux.org>
Sun, 14 Jul 2002 19:50:17 +0000 (19:50 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    atlantic.c -> 1.1

atlantic.c [new file with mode: 0644]

diff --git a/atlantic.c b/atlantic.c
new file mode 100644 (file)
index 0000000..6b2dc18
--- /dev/null
@@ -0,0 +1,368 @@
+/* atlantic.c: Setup program for AT/LANTIC DP83905 ethercards. */
+/*
+       This is a setup and diagnostic program for ISA NE2000 Ethernet adapters.
+       It has specific support for configuring the National Semiconductor
+       AT/LANTIC DP83905 used in on ISA Ethernet adapters such as the NE2000plus.
+       It also works several work-alike chips from other vendors.
+
+       This program must be compiled with '-O'.
+       If you have unresolved references to e.g. inw(), then you haven't used -O.
+       The suggested compile command is at the bottom of this file.
+
+       Copyright 1994-2000 by Donald Becker.
+       This software may be used and distributed according to the terms of
+       the GNU General Public License (GPL), incorporated herein by reference.
+       Contact the author for use under other terms.
+
+       The author may be reached as becker@scyld.com, or C/O
+        Scyld Computing Corporation
+        410 Severn Ave., Suite 210
+        Annapolis MD 21403
+
+       Support and updates are available at
+       http://www.scyld.com/diag/index.html
+
+       Common-sense licensing statement: Using any portion of this program in
+       your own program means that you must give credit to the original author
+       and release the resulting code under the GPL.  You must include the
+       text of the license with any redistribution.  See
+        http://www.gnu.org/copyleft/gpl.txt
+*/
+#if 0
+static char vcid[] = "$Id$";
+#endif
+
+static char *version_msg =
+"atlantic.c v1.01 7/23/00 Donald Becker http://www.scyld.com/diag/index.html\n";
+static char *usage_msg =
+"Usage: atlantic [-afhNsvVwW] [-p <IOport>] [-F <xcvr-type>] [-P <newIOport>]
+   -p <I/O base address>       Use the card at this I/O address (default 0x300).
+  EEPROM configuration commands take effect at the next reset
+   -F 10baseT, 10base2, AUI, 10baset   Set the specified transceiver type.
+   -Q 3, 4, 5, 9, 10, 11, 12, 15       Set the IRQ line.
+   -P 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0x360  New I/O base.
+   -N or -W         Set to NE2000 or WD8013 clone mode (mutually exclusive)
+";
+
+#if ! defined(__OPTIMIZE__)
+#warning  You must compile this program with the correct options!
+#error You must compile this driver with "-O".
+#endif
+#include <unistd.h>                            /* Hey, we're all POSIX here, right? */
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#if defined(__linux__)  &&  __GNU_LIBRARY__ == 1
+#include <asm/io.h>                    /* Newer libraries use <sys/io.h> instead. */
+#else
+#include <sys/io.h>
+#endif
+
+/* Two functions that some GLIBC header file sets omit.  grrr... */
+extern int ioperm(unsigned long __base, unsigned long extent, int on_or_off);
+extern int iopl(int level);
+
+struct option longopts[] = {
+ /* { name     has_arg  *flag  val } */
+       {"base-address", 1, 0, 'p'}, /* Base I/O port address. */
+       {"help",           0, 0, 'h'},  /* Give help */
+       {"interface",  0, 0, 'F'},      /* Set the transceiver type (built-in, AUI) */
+       {"NE2000",         1, 0, 'N'},  /* Set to NE2000 mode */
+       {"new_ioport", 1, 0, 'P'},      /* Set a I/O location for the card. */
+       {"irq",            1, 0, 'Q'},  /* Set a new IRQ (interrupt) line. */
+       {"wd8013",         1, 0, 'W'},  /* Set to WD8013 mode */
+       {"verbose",        0, 0, 'v'},  /* Verbose mode */
+       {"version",        0, 0, 'V'},  /* Display version number */
+       {"write-EEPROM", 1, 0, 'w'},/* Write th EEPROMS with the specified vals */
+       { 0, 0, 0, 0 }
+};
+
+/* Three configuration registers are read and may be set from the EEPROM.
+   They are named registers A, B and C
+
+   RegA                NE/WD   FREAD  INT2   INT1   INT0  IOAD2  IOAD1  IOAD0
+   RegB                EELOAD  BTPR   BUSE   CHRDY  IO16  GDLINK XCVR1  XCVR0
+   RegC                SoftEn  ClkSel IntMde COMP   BtPR3 BtPR2  BtPR1  BtPROM0
+*/
+/* I/O base settings, IOAD2-0, in register A. */
+static int io_base[8] = {
+       0x300, 0x278, 0x240, 0x280, 0x2C0, 0x320, 0x340, 0x360};
+/* The IRQ line settings, INT2-0, in register A, and a reverse map. */
+static int index2irq[8] = {3, 4, 5, 9, 10, 11, 12, 15};
+static int irq2index[16] = {-1, -1, 3, 0, 1, 2, -1, -1,
+                                                       -1, 3, 4, 5, 6, -1, -1, 7};
+/* The transceiver settings, XCVR1-0, in register B.
+   10baseT-LRT is Low Receive Threshold -- "turning the volume up" for long
+   wiring runs.
+*/
+static char *xcvr_name[4] = {"10baseT", "Thinnet", "AUI", "10baseT (LRT)"};
+
+int opt_f = 0;
+
+static void show_config(int regA, int regB);
+static void write_EEPROM(int dp8390_base, int regA, int regB, int regC);
+
+\f
+/*
+ I should say something here... uuhhhhmmm....
+ */
+
+int
+main(int argc, char *argv[])
+{
+       extern char *optarg;
+       int port_base = 0x300;          /* Base address of the board. */
+       int     ioaddr = 0x300;                 /* Base address of the 8390 registers. */
+       int new_ioport = -1, new_irq = -1, new_mode = 0;
+       int errflag = 0, verbose = 0, wd_mode = 0, write_eeprom = 0;
+       int show_version = 0, opt_a = 0;
+       int new_io_idx = -1, xcvr = -1; /* I/O port, Transceiver type to set. */
+       int regA, regB, old_regA, old_regB;
+       int option;
+
+       while ((option = getopt(argc, argv, "afF:hi:Q:m:Np:P:vVwW")) != -1)
+               switch (option) {
+               case 'a':  opt_a++; break;
+               case 'f':  opt_f++; break;
+               case 'F':
+                       if (strncmp(optarg, "10base", 6) == 0) {
+                               switch (optarg[6]) {
+                               case 'T':  xcvr = 0; break;
+                               case '2':  xcvr = 1; break;
+                               case '5':  xcvr = 2; break;
+                               default: errflag++;
+                               }
+                       } else if (strcmp(optarg, "AUI") == 0)
+                               xcvr = 2;
+                       else if (optarg[0] >= '0' &&  optarg[0] <= '3'
+                                        &&  optarg[1] == 0)
+                               xcvr = optarg[0] - '0';
+                       else {
+                               fprintf(stderr, "Invalid interface specified: it must be"
+                                               " 0..3, '10base{T,2,5}' or 'AUI'.\n");
+                               errflag++;
+                       }
+                       break;
+               case 'h':  printf(usage_msg); return 0;
+               case 'N':  wd_mode = 0; new_mode = 2; break;
+               case 'i':
+               case 'Q':
+                       new_irq = atoi(optarg);
+                       if (new_irq < 3 || new_irq > 15 || new_irq == 6 || new_irq == 8) {
+                               fprintf(stderr, "Invalid new IRQ %#x.  Valid values: "
+                                               "3-5,7,9-15.\n", new_irq);
+                               errflag++;
+                       }
+                       break;
+               case 'p':  port_base = strtol(optarg, NULL, 16);  break;
+               case 'P':  new_ioport = strtol(optarg, NULL, 16);  break;
+               case 'v':  verbose++;    break;
+               case 'V':  show_version++;               break;
+               case 'w':  write_eeprom++;               break;
+               case 'W':  wd_mode++; new_mode = 1; break;
+               case '?':
+                       errflag++;
+               }
+       if (errflag) {
+               fprintf(stderr, usage_msg);
+               return 3;
+       }
+
+       if (verbose || show_version)
+               printf(version_msg);
+
+       /* Turn on access to the I/O ports. */
+       if (ioperm(port_base, 32, 1) < 0) {
+               perror("atlantic: io-perm");
+               fprintf(stderr, "       (You must run this program with 'root' permissions.)\n");
+               return 2;
+       }
+
+       /* Check the specified new I/O port value. */
+       if (new_irq >= 0  &&  (new_irq >= 16  ||  irq2index[new_irq] < 0)) {
+               fprintf(stderr, "The new IRQ line, %d, is invalid.\n",
+                               new_irq);
+               return 3;
+       }
+       if (new_ioport >= 0) {
+               int i;
+               for (i = 0; i < 8; i++)
+                       if (new_ioport == io_base[i])
+                                break;
+               if (i >= 8) {
+                       fprintf(stderr, "The new base I/O address, %#x, is invalid.\n",
+                                       new_ioport);
+                       return 3;
+               }
+               new_io_idx = i;
+       }
+
+       if ( ! opt_f  &&  inb(port_base) == 0xff) {
+               printf("No AT/LANTIC chip found at I/O %#x.\n"
+                          " Use '-f' to override if you are certain the chip is at this"
+                          " I/O location.\n", port_base);
+               return 1;
+       }
+               
+       /* First find if this card is set to WD or NE mode by locating the 8390
+          registers. */
+       {
+               int saved_cmd = inb(port_base);
+               int cntr;
+               outb(0x20, port_base);
+               inb(port_base + 13);    /* Clear a counter register */
+               cntr = inb(port_base + 13);
+               if (verbose)
+                       printf("  The NE2K 8390 cmd register was %2.2x, cntr %d.\n",
+                                  saved_cmd, cntr);
+               if (cntr)
+                       ioaddr = port_base + 16;
+               else
+                       ioaddr = port_base;
+               outb(saved_cmd, port_base);
+       }
+
+       if (opt_a) {
+               int saved_0 = inb(port_base);
+               int window, i;
+
+               printf("8390 registers at %#x (command register was %2.2x)\n",
+                          ioaddr, saved_0);
+               for (window = 0; window < 4; window++) {
+                       printf(" Window %d:", window);
+                       outb((window<<6) | 0x20, ioaddr);
+                       for(i = 0; i < 16; i++) {
+                               if (window == 0 && i == 6)
+                                       printf(" **");
+                               else
+                                       printf(" %2.2x", inb(ioaddr + i));
+                       }
+                       printf(".\n");
+               }
+               if (ioaddr != port_base) {                              /* WD emulation. */
+                       printf("WD8013 compatible registers: ");
+                       for(i = 0; i < 16; i++) {
+                               printf(" %2.2x", inb(port_base + i));
+                               fflush(stdout);
+                       }
+                       printf(".\n");
+               }
+       }
+
+       printf("Reading the configuration from the AT/LANTIC at %#3x...\n",
+                  port_base);
+       outb(0x21, ioaddr);                     /* Select Window 0 */
+       old_regA = regA = inb(ioaddr + 0x0A);
+       old_regB = regB = inb(ioaddr + 0x0B);
+
+       printf("The current configuration is\n");
+       show_config(regA, regB);
+
+       /* This should never be triggered.  We see the card after all!*/
+       if ((regA & 7) == 1)
+               printf(" Your card is set to be configured at boot-time.\n"
+                          "  Remaining with this software configuration is a bad idea"
+                          " when using\n  modern systems.  The card will likely be"
+                          " unintentionally activated at\n  unexpected I/O and IRQ"
+                          " settings.\n" );
+
+       if (new_mode)
+               regA = (regA & ~0x80) | (new_mode == 1  ? 0x80 : 0);
+       if (new_irq >= 0)
+               regA = (regA & ~0x38) | (irq2index[new_irq]<<3);
+       if (new_io_idx >= 0)
+               regA = (regA & ~0x07) | new_io_idx;
+       if (xcvr >= 0)
+               regB = (regB & 0x5C) | (xcvr & 0x3);
+
+       if (regA != old_regA || regB != old_regB || write_eeprom) {
+               printf("The proposed new configuration is\n");
+               show_config(regA, regB);
+               if ( ! write_eeprom)
+                       printf(" Use '-w' to set this as the current configuration "
+                                  "(valid until next reset).\n"
+                                  " Use '-w -w' to write the settings to the EEPROM.\n"
+                                  " Use '-w -w -w' to do both.\n");
+       }
+
+       /* We must write the EEPROM and register B before possibly moving the
+          I/O base. */
+       if (write_eeprom > 1) {
+               printf("Writing the new configuration to the EEPROM...\n");
+               write_EEPROM(ioaddr, regA, regB, 0x30);
+               printf("Wrote the EEPROM at %#3x with 0x%2.2x 0x%2.2x 0x%2.2x.\n",
+                          port_base, regA, regB, 0x30);
+       }
+
+       if (write_eeprom & 1) {
+               if (regB != old_regB) {
+                       printf(" Setting register B to %#02x.\n", regB);
+                       inb(ioaddr + 0x0B);
+                       outb(regB, ioaddr + 0x0B);
+                       regB = inb(ioaddr + 0x0B);
+                       printf(" Register B is now %#02x:  Interface %s.\n", regB,
+                                  xcvr_name[regB & 0x03]);
+               }
+               if (regA != old_regA) {
+                       printf(" Setting register A to %#02x (%s mode I/O %#x IRQ %d).\n",
+                                  regA, regA & 0x80 ? "WD8013" : "NE2000",
+                                  io_base[regA & 0x07], index2irq[(regA >> 3) & 0x07] );
+                       inb(ioaddr + 0x0A);
+                       outb(regA, ioaddr + 0x0A);
+                       if (port_base == io_base[regA&7]) {
+                               ioaddr = port_base + (regA & 0x80 ? 16 : 0);
+                               printf(" Register A at base %x is now %#02x.\n",
+                                          ioaddr, inb(ioaddr + 0x0A));
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static void show_config(int regA, int regB)
+{
+       printf("  Register A 0x%2.2x:  I/O base @ %#x, IRQ %d,"
+                  " %s mode, %s ISA read.\n",
+                  regA, io_base[regA & 0x07], index2irq[(regA >> 3) & 0x07],
+                  regA & 0x80 ? "WD8013" : "NE2000",
+                  regA & 0x40 ? "fast" : "normal" );
+       printf("  Register B 0x%2.2x:  Interface %s.\n", regB,
+                  xcvr_name[regB & 0x03]);
+       printf("    Boot PROM writes are %sabled, CHRDY after %s%s.\n",
+                  regB & 0x40 ? "en" : "dis",
+                  regB & 0x10 ? "BALE" : "IORD/IOWR",
+                  regB & 0x08 ? ", IO16 after IORD/IOWR" : "");
+       if (regB & 0x20)
+               printf("    Bus error detected.\n");
+}
+
+/* Write the A, B, and C configuration registers into the EEPROM at
+   DP8390_BASE.
+   Ideally this would be done with interrupts disabled, but we do not have
+   that capability with user level code.
+*/
+static void write_EEPROM(int dp8390_base, int regA, int regB, int regC)
+{
+       int ioregb = dp8390_base + 0x0B;
+       int currB = inb(ioregb) & (~0x04) ;
+
+       outb(currB | 0x80, ioregb);
+       inb(ioregb);
+       outb(regA, ioregb);
+       outb(regB, ioregb);
+       outb(regC, ioregb);
+       return;
+}
+\f
+/*
+ * Local variables:
+ *  compile-command: "gcc -Wall -Wstrict-prototypes -O6 -o atlantic atlantic.c"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
This page took 0.085064 seconds and 4 git commands to generate.