Linux-Hardware Digest #713, Volume #10            Fri, 9 Jul 99 06:13:43 EDT

Contents:
  Re: 2 x 3c905 @ same I/O ??? (Ratz)

----------------------------------------------------------------------------

From: Ratz <[EMAIL PROTECTED]>
Crossposted-To: comp.os.linux.misc,comp.os.linux.networking
Subject: Re: 2 x 3c905 @ same I/O ???
Date: Fri, 09 Jul 1999 11:13:55 +0200

This is a multi-part message in MIME format.
==============F353063F8B284B69DF864337
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit


Hi
Ok, I'm quite busy, so here are two proggys to manage the problem.

bye,

ratz
==============F353063F8B284B69DF864337
Content-Type: text/plain; charset=iso-8859-1;
 name="3c5x9setup.c"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline;
 filename="3c5x9setup.c"

/* 3c5x9setup.c: Setup program for 3Com EtherLink III ethercards.

   Copyright 1994-1996 by Donald Becker.
   This version released under the Gnu Public Lincese, incorporated herei=
n
   by reference.  Contact the author for use under other terms.

   This is a EEPROM setup and diagnostic program for the 3Com 3c5x9 serie=
s
   ethercards.

   This program must be compiled with "-O"!  See the bottom of this file
   for the suggested compile-command.

   The author may be reached as [EMAIL PROTECTED]
   C/O USRA-CESDIS, Code 930.5 Bldg. 28, Nimbus Rd., Greenbelt MD 20771
*/

static char *version_msg =3D
"3c5x9setup.c:v0.04 12/11/96 Donald Becker ([EMAIL PROTECTED])\=
n";
static char *usage_msg =3D
"Usage: 3c5x9 [-aEfFsvVw] [-p <IOport>] [-F 10baseT|10base2|AUI>] [-Q <IR=
Q>]\n";

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <strings.h>
#include <linux/in.h>
#include <asm/io.h>

struct option longopts[] =3D {
 /* { name  has_arg  *flag  val } */
        {"base-address", 1, 0, 'p'},
        {"new-base-address", 1, 0, 'P'},
        {"show_all_registers",  0, 0, 'a'},     /* Print all registers. */
        {"help",        0, 0, 'h'},     /* Give help */
        {"emergency-rewrite",  0, 0, 'E'}, /* Re-write a corrupted EEPROM.  */
        {"force-detection",  0, 0, 'f'},
        {"new-interface",  1, 0, 'F'},  /* New interface (built-in, AUI, etc.) */=

        {"new-IOaddress",       1, 0, 'P'},     /* New base I/O address. */
        {"new-irq",     1, 0, 'Q'},             /* New interrupt number */
        {"verbose",     0, 0, 'v'},             /* Verbose mode */
        {"version", 0, 0, 'V'},         /* Display version number */
        {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals *=
/
        { 0, 0, 0, 0 }
};

/* Offsets from base I/O address. */
#define EL3_DATA 0x00
#define EL3_CMD 0x0e
#define EL3_STATUS 0x0e

#define  EEPROM_READ 0x80
#define  EEPROM_WRITE 0x40
#define  EEPROM_ERASE 0xC0
#define  EEPROM_EWENB 0x30              /* Enable erasing/writing for 10 msec. */
#define  EEPROM_EWDIS 0x00              /* Enable erasing/writing for 10 msec. */

#define EL3WINDOW(win_num) outw(0x0800+(win_num), ioaddr + EL3_CMD)

/* Register window 1 offsets, used in normal operation. */
#define TX_FREE 0x0C
#define TX_STATUS 0x0B
#define TX_FIFO 0x00
#define RX_FIFO 0x00

/* EEPROM operation locations. */
enum eeprom_offset {
        PhysAddr01=3D0, PhysAddr23=3D1, PhysAddr45=3D2, ModelID=3D3,
        EtherLink3ID=3D7, IFXcvrIO=3D8, IRQLine=3D9,
        AltPhysAddr01=3D10, AltPhysAddr23=3D11, AltPhysAddr45=3D12,
        DriverTune=3D13, Checksum=3D15};

/* Last-hope recovery major boo-boos: rewrite the EEPROM with the values
   from my card (and hope I don't met you on the net...). */
unsigned short djb_eeprom[16] =3D {
        0x0020, 0xaf0e, 0x3bc2, 0x9058, 0xbc4e, 0x0036, 0x4441, 0x6d50,
        0x0090, 0xaf00, 0x0020, 0xaf0e, 0x3bc2, 0x1310, 0x0000, 0x343c, }; =

/* Values read from the EEPROM, and the new image. */
unsigned short eeprom_contents[16];
unsigned short new_ee_contents[16];

int do_write_eeprom =3D 0;
int ioaddr;

static void print_eeprom(unsigned short *eeprom_contents);
static void write_eeprom(short ioaddr, int index, int value);
static unsigned int calculate_checksum(unsigned short *values);
static int do_update(unsigned short *ee_values,
                                         int index, char *field_name, int new_value);
=0C
int
main(int argc, char **argv)
{
        int port_base =3D 0x300;
        int new_interface =3D -1, new_irq =3D -1, new_ioaddr =3D -1;
        int errflag =3D 0, opt_f =3D 0, verbose =3D 0, show_version =3D 0;
        int emergency_rewrite =3D 0;
        int dump_all_regs =3D 0;
        int c, longind, i, j, saved_window;
        extern char *optarg;

        while ((c =3D getopt_long(argc, argv, "aEfF:i:p:P:Q:svVw",
                                                        longopts, &longind))
                   !=3D -1)
                switch (c) {
                case 'a': dump_all_regs++;               break;
                case 'E': emergency_rewrite++;   break;
                case 'f': opt_f++; break;
                case 'F':
                        if (strncmp(optarg, "10base", 6) =3D=3D 0) {
                                switch (optarg[6]) {
                                case 'T':  new_interface =3D 0; break;
                                case '2':  new_interface =3D 3; break;
                                case '5':  new_interface =3D 1; break;
                                default: errflag++;
                                }
                        } else if (strcmp(optarg, "AUI") =3D=3D 0)
                                new_interface =3D 1;
                        else if (optarg[0] >=3D '0' &&  optarg[0] <=3D '3'
                                           &&  optarg[1] =3D=3D 0)
                                new_interface =3D optarg[0] - '0';
                        else {
                                fprintf(stderr, "Invalid interface specified: it must 
be"
                                                " 0..3, '10base{T,2,5}' or 'AUI'.\n");
                                errflag++;
                        }
                        break;
                case 'Q':
                        new_irq =3D atoi(optarg);
                        if (new_irq < 3 || new_irq > 15 || new_irq =3D=3D 6 || new_irq 
=3D=3D =
8) {
                                fprintf(stderr, "Invalid new IRQ %#x.  Valid values: "
                                                "3-5,7,9-15.\n", new_irq);
                                errflag++;
                        }
                        break;
                case 'p':
                        port_base =3D strtol(optarg, NULL, 16);
                        break;
                case 'P':
                        new_ioaddr =3D strtol(optarg, NULL, 16);
                        if (new_ioaddr < 0x200 || new_ioaddr > 0x3f0) {
                                fprintf(stderr, "Invalid new I/O address %#x.  Valid 
range "
                                                "0x200-0x3f0.\n", new_ioaddr);
                                errflag++;
                        }
                        break;
                case 'v': verbose++;             break;
                case 'V': show_version++;                break;
                case 'w': do_write_eeprom++;     break;
                case '?':
                        errflag++;
                }
        if (errflag) {
                fprintf(stderr, usage_msg);
                return 3;
        }

        if (ioperm(port_base, 16, 1) < 0) {
                perror("3c5x9setup: ioperm()");
                fprintf(stderr, "This program must be run as root.\n");
                return 2;
        }

        if (verbose)
                printf(version_msg);

        ioaddr =3D port_base;

        saved_window =3D inw(ioaddr + EL3_STATUS);
        if (!opt_f  && (saved_window & 0xe000) =3D=3D 0x2000) {
                printf("A potential 3c5*9 has been found, but it appears to still "
                           "be active.\nEither shutdown the network, or use the"
                           " '-f' flag.\n");
                return 1;
        }

        EL3WINDOW(0);
        if (inw(port_base) =3D=3D 0x6d50) {
                printf("3c5x9 found at %#3.3x.\n", port_base);
        } else {
                printf("3c5*9 not found at %#3.3x, status %4.4x.\n"
                           "If there is a 3c5*9 card in the machine, explicitly set 
the"
                           " I/O port address\n  using '-p <ioaddr>\n",
                           port_base, inw(port_base));
                if (opt_f < 2)
                        return 1;
        }

        if (dump_all_regs) {
                for (j =3D 0; j < 8; j++) {
                        int i;
                        printf("Window %d:", j);
                        outw(0x0800 + j, ioaddr + 0x0e);
                        for (i =3D 0; i < 16; i+=3D2)
                                printf(" %4.4x", inw(ioaddr + i));
                        printf(".\n");
                }
        }

        EL3WINDOW(0);

        /* Read the EEPROM. */
        for (i =3D 0; i < 16; i++) {
                outw(EEPROM_READ + i, ioaddr + 10);
                /* Pause for at least 162 us. for the read to take place. */
                usleep(162);
                eeprom_contents[i] =3D inw(ioaddr + 12);
                if (verbose)
                        printf("EEPROM index %d: %4.4x.\n", i, eeprom_contents[i]);
        }

        if (emergency_rewrite) {
                if (emergency_rewrite < 3  ||  !do_write_eeprom)
                        printf(" Caution!  Last-chance EEPROM write requested.  The\n"
                                   " new EEPROM values will not be written without"
                                   " '-E -E -E -w' flags.\n");
                else {
                        for (i =3D 0; i < 16; i++) {
                                eeprom_contents[i] =3D djb_eeprom[i];
                                write_eeprom(ioaddr, i, eeprom_contents[i]);
                        }
                }
        }
        {
                unsigned short new_ifxcvrio =3D eeprom_contents[IFXcvrIO];
                unsigned short new_irqline =3D eeprom_contents[IRQLine];
                int something_changed =3D 0;

                if (new_interface >=3D 0)
                        new_ifxcvrio =3D (new_interface << 14) | (new_ifxcvrio & 
0x3fff);
                if (new_ioaddr > 0)
                        new_ifxcvrio =3D ((new_ioaddr>>4) & 0x1f) | (new_ifxcvrio & 
0xffe0);
                if (new_irq > 0)
                        new_irqline =3D (new_irq << 12) | 0x0f00;

                if (do_update(eeprom_contents, IRQLine, "IRQ", new_irqline))
                        something_changed++;

                if (do_update(eeprom_contents, IFXcvrIO, "transceiver/IO",
                                          new_ifxcvrio))
                        something_changed++;

                /* To change another EEPROM value write it here. */

                if (do_update(eeprom_contents, Checksum, "checksum",
                                          calculate_checksum(eeprom_contents)))
                        something_changed++;

                if (something_changed  &&  !do_write_eeprom)
                        printf(" (The new EEPROM values will not be written without"
                                        " the '-w' flag.)\n");
        }

        print_eeprom(eeprom_contents);

        EL3WINDOW(saved_window>>13);

        return 0;
}

static void print_eeprom(unsigned short *eeprom_contents)
{
        unsigned char *phys_addr;
        char *if_names[] =3D {"10baseT", "AUI", "undefined", "BNC"};
        int i;

        printf("Model number 3c%2.2x%1.1x version %1.1x, base I/O %#x,"
                   " IRQ %d, %s port.\n",
                   eeprom_contents[ModelID] & 0x00ff,
                   eeprom_contents[ModelID] >> 12,
                   (eeprom_contents[ModelID] >> 8) & 0x000f,
                   0x200 + ((eeprom_contents[IFXcvrIO] & 0x1f) << 4),
                   eeprom_contents[IRQLine] >> 12,
                   if_names[eeprom_contents[IFXcvrIO] >> 14]);

        phys_addr =3D (unsigned char *)(eeprom_contents + PhysAddr01);
        printf("Primary physical address is %2.2x", phys_addr[1]);
        for (i =3D 1; i < 6; i++)
                printf(":%2.2x", phys_addr[i^1]);

        phys_addr =3D (unsigned char *)(eeprom_contents + AltPhysAddr01);
        printf("\nAlternate physical address is %2.2x", phys_addr[1]);
        for (i =3D 1; i < 6; i++)
                printf(":%2.2x", phys_addr[i^1]);
        printf("\n");

        if (calculate_checksum(eeprom_contents) !=3D eeprom_contents[Checksum])
                printf("****CHECKSUM ERROR****: Calcuated checksum: %4.4x, "
                           "stored checksum %4.4x.\n",
                           calculate_checksum(eeprom_contents),
                           eeprom_contents[Checksum]);
}


static void write_eeprom(short ioaddr, int index, int value)
{
        outw(value, ioaddr + 12);
        outw(EEPROM_EWENB, ioaddr + 10);
        usleep(60);
        outw(EEPROM_ERASE + index, ioaddr + 10);
        usleep(60);
        outw(EEPROM_EWENB, ioaddr + 10);
        usleep(60);
        outw(value, ioaddr + 12);
        outw(EEPROM_WRITE + index, ioaddr + 10);
        usleep(10000);
}

/* Calculate the EEPROM checksum.
   The checksum for the fixed values is returned in the high byte.
   The checksum for the programmable variables is in the low the byte.
   */

static unsigned int
calculate_checksum(unsigned short *values)
{
        int fixed_checksum =3D 0, var_checksum =3D 0;
        int i;

        for (i =3D 0; i <=3D 14; i++) {                         /* Note: 14 (loc. 15 
is the sum) */
                if (i =3D=3D IFXcvrIO || i =3D=3D IRQLine || i =3D=3D DriverTune)
                        var_checksum ^=3D values[i];
                else
                        fixed_checksum ^=3D values[i];
        }
        return ((fixed_checksum ^ (fixed_checksum << 8)) & 0xff00) |
                ((var_checksum ^ (var_checksum >> 8)) & 0xff);
}

static int do_update(unsigned short *ee_values,
                                         int index, char *field_name, int new_value)
{
        if (ee_values[index] !=3D new_value) {
                if (do_write_eeprom) {
                        printf("Writing new %s entry 0x%4.4x.\n",
                                   field_name, new_value);
                        write_eeprom(ioaddr, index, new_value);
                } else
                        printf(" Would write new %s entry 0x%4.4x (old value 
0x%4.4x).\n",
                                   field_name, new_value, ee_values[index]);
                ee_values[index] =3D new_value;
                return 1;
        }
        return 0;
}

=0C
/*
 * Local variables:
 *  compile-command: "cc -N -O -Wall -o 3c5x9 3c5x9setup.c"
 *  tab-width: 4
 *  c-indent-level: 4
 * End:
 */

==============F353063F8B284B69DF864337
Content-Type: text/plain; charset=iso-8859-1;
 name="vortex-diag.c"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline;
 filename="vortex-diag.c"

/* vortex-diag.c: Diagnostics/EEPROM setup for the 3Com Vortex series.

   This is a diagnostic and EEPROM setup program for Ethernet adapters
   based on the 3Com Vortex, Boomerang and Cyclone chips, as used on the
   3Com 3c590/595/900/905 PCI EtherLink XL adapters.

   Copyright 1997-1999 by Donald Becker.
   This version released under the Gnu Public License, incorporated herei=
n
   by reference.  Contact the author for use under other terms.

   This program must be compiled with "-O"!  See the bottom of this file
   for the suggested compile-command.

   The author may be reached as [EMAIL PROTECTED]
   C/O USRA-CESDIS, Code 930.5 Bldg. 28, Nimbus Rd., Greenbelt MD 20771

   References

   3Com Vortex Engineering Release Specification
   3Com Boomerang modifications (unreleased)
   http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
   http://www.national.com/pf/DP/DP83840.html
*/

static char *version_msg =3D
"vortex-diag.c:v1.08e 6/23/99 Donald Becker ([EMAIL PROTECTED])=
\n";
static char *usage_msg =3D
"Usage: vortex-diag [-aBEfFsvVw] [-p <IOport>].\n";

#if !defined(__OPTIMIZE__)
#warning  You must compile this program with the correct options!
#warning  See the last lines of the source file.
#error You must compile this driver with "-O".
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <getopt.h>
#include <strings.h>
#include <errno.h>
#if defined(__linux__)  &&  __GNU_LIBRARY__ =3D=3D 1
#include <asm/io.h>                     /* Newer libraries use <sys/io.h> instead. */
#else
#include <sys/io.h>
#endif

/* No libmii.h (yet) */
extern show_mii_details(int ioaddr, int phy_id);
extern monitor_mii(int ioaddr, int phy_id);
/* No libflash.h  */
extern int flash_show(long addr_ioaddr, long data_ioaddr);
extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename)=
;
extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filena=
me);

/* We should use __u8 .. __u32, but they are not always defined. */
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;

struct option longopts[] =3D {
 /* { name  has_arg  *flag  val } */
        {"Advertise", 1, 0, 'A'},
        {"base-address", 1, 0, 'p'},
        {"show_all_registers",  0, 0, 'a'},     /* Print all registers. */
        {"help",        0, 0, 'h'},     /* Give help */
        {"show-eeprom",  0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */
        {"emergency-rewrite",  0, 0, 'E'}, /* Re-write a corrupted EEPROM.  */
        {"force-detection",  0, 0, 'f'},
        {"new-interface",  1, 0, 'F'},  /* New interface (built-in, AUI, etc.) */=

        {"new-hwaddr",  1, 0, 'H'},     /* Set a new hardware address. */
        {"show-mii",  0, 0, 'm'},       /* Dump MII management registers. */
        {"port-base",  1, 0, 'p'},      /* Use the specified I/O address. */
        {"quiet",       0, 0, 'q'},             /* Decrease verbosity */
        {"Reset",               0, 0, 'R'},     /* Reset the transceiver. */
        {"chip-type",  1, 0, 't'},      /* Assume the specified chip type index. */
        {"quiet",       0, 0, 'q'},             /* Decrease verbosity */
        {"test",        0, 0, 'T'},             /* Do register and SRAM test. */
        {"verbose",     0, 0, 'v'},             /* Verbose mode */
        {"version", 0, 0, 'V'},         /* Display version number */
        {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals *=
/
        { 0, 0, 0, 0 }
};

extern int vortex_diag(int vendor_id, int dev_id, int ioaddr, int part_id=
x);

/* Chip-specific flags. Yes, it's grungy to have the enum here. */
enum { HAS_FLASH_BUG=3D1, ROADRUNNER=3D2 };

/* This table is searched in order: place specific entries followed by
   'catch-all' general entries. */
struct pcidev_entry {
        char *proc_pci_name;
        char *part_name;
        int vendor, device, device_mask;
        int flags;
        int io_size;
        int (*diag_func)(int vendor_id, int device_id, int ioaddr, int part_num)=
;
} pcidev_tbl[] =3D {
        {"3Com Vortex/Boomerag/Cyclone", "3Com Generic Vortex/Boomerag/Cyclone",=

         0x10B7, 0x9999, 0xffff, 0, 256, vortex_diag},
        {"3Com Vortex (rev ", "3Com 3c590 Vortex 10Mbps",
         0x10B7, 0x5900, 0xffff, 0, 256, vortex_diag},
        {"3Com EISA Vortex", "3c592 EISA 10mbps Demon/Vortex",
         0x10B7, 0x5920, 0xffff, 0, 256, vortex_diag},
        {"3Com Vortex (rev ", "3Com 3c595 Vortex 10/100baseTx",
         0x10B7, 0x5950, 0xffff, 0, 256, vortex_diag},
        {"3Com Vortex (rev ", "3Com 3c595 Vortex 10/100baseT4",
         0x10B7, 0x5951, 0xffff, 0, 256, vortex_diag},
        {"3Com Vortex (rev ", "3Com 3c595 Vortex 10/100baseT-MII",
         0x10B7, 0x5952, 0xffff, 0, 256, vortex_diag},
        {"3Com EISA Vortex", "3c597 EISA Fast Demon/Vortex",
         0x10B7, 0x5970, 0xffff, 0, 256, vortex_diag},
        {"3Com 3C900", "3c900 Boomerang 10baseT",
         0x10B7, 0x9000, 0xffff, 0, 256, vortex_diag},
        {"3Com 3C900", "3c900 Boomerang 10Mbps Combo",
         0x10B7, 0x9001, 0xffff, 0, 256, vortex_diag},
        {"3Com 3C900", "3c900 Cyclone 10Mbps TPO",
         0x10B7, 0x9004, 0xffff, 0, 256, vortex_diag},
        {"3Com 3C900", "3c900 Cyclone 10Mbps Combo",
         0x10B7, 0x9005, 0xffff, 0, 256, vortex_diag},
        {"3Com 3C900", "3c900 Cyclone 10Mbps TPC",
         0x10B7, 0x9006, 0xffff, 0, 256, vortex_diag},
        {"3Com 3C905", "3c905 Boomerang 100baseTx",
         0x10B7, 0x9050, 0xffff, 0, 256, vortex_diag},
        {"3Com 3C905", "3c905 Boomerang 100baseT4",
         0x10B7, 0x9051, 0xffff, 0, 256, vortex_diag},
        {"3Com 3C905", "3c905B Cyclone 100baseTx",
         0x10B7, 0x9055, 0xffff, HAS_FLASH_BUG, 256, vortex_diag},
        {"3Com 3C905BNC", "3c905B Cyclone 10/100/BNC",
         0x10B7, 0x9058, 0xffff, HAS_FLASH_BUG, 256, vortex_diag},
        {"3Com 3C905B-FX", "3c905B Cyclone 100baseFx",
         0x10B7, 0x905A, 0xffff, HAS_FLASH_BUG, 256, vortex_diag},
        {"3Com 3C905C", "3c905C Tornado 100baseTx",
         0x10B7, 0x9200, 0xff00, HAS_FLASH_BUG, 256, vortex_diag},
        {"3Com 3C980", "3c980 Cyclone, server edition",
         0x10B7, 0x9800, 0xffff, HAS_FLASH_BUG, 256, vortex_diag},
        {"3Com 3cSOHO100-TX", "3cSOHO100-TX Hurricane",
         0x10B7, 0x7646, 0xff00, HAS_FLASH_BUG, 256, vortex_diag},
        {"3c555 Laptop Hurricane",      "3c555 Laptop Hurricane",
         0x10B7, 0x5055, 0xffff, HAS_FLASH_BUG, 256, vortex_diag},
        {"3Com 3CCFE556", "3ccfe556 Roadrunner PCMCIA",
         0x0101, 0x0556, 0xffff, ROADRUNNER, 32, vortex_diag},
        { 0, 0, 0, 0},
};

int verbose =3D 1, opt_f =3D 0, debug =3D 0;
int show_regs =3D 0, show_eeprom =3D 0, show_mii =3D 0;
unsigned int opt_a =3D 0,                                       /* Show-all-interfaces 
flag. */
        opt_restart =3D 0,
        opt_reset =3D 0,
        opt_watch =3D 0;
unsigned int opt_GPIO =3D 0;            /* General purpose I/O setting. */
int do_write_eeprom =3D 0, do_test =3D 0;
int nway_advertise =3D 0, fixed_speed =3D -1;
int new_default_media =3D -1;
static unsigned int opt_flash_show =3D 0;
static char     *opt_flash_dumpfile =3D NULL, *opt_flash_loadfile =3D NULL;
static int opt_dma_diag =3D 0;
static unsigned char new_hwaddr[6], set_hwaddr =3D 0;
static unsigned set_ee_rom =3D 0;

static int scan_proc_pci(int card_num);
static int parse_media_type(const char *capabilities);
static int get_media_index(const char *name);

=0C
int
main(int argc, char **argv)
{
        int port_base =3D 0, chip_type =3D 0;
        int errflag =3D 0, show_version =3D 0;
        int emergency_rewrite =3D 0;
        int c, longind;
        int card_num =3D 0;
        extern char *optarg;

        while ((c =3D getopt_long(argc, argv, "#:aA:DeEfF:G:mp:PqrRst:vVwWgH:BL:=
S:",
                                                        longopts, &longind))
                   !=3D -1)
                switch (c) {
                case '#': card_num =3D atoi(optarg);    break;
                case 'a': show_regs++; opt_a++;         break;
                case 'A': nway_advertise =3D parse_media_type(optarg); break;
                case 'D': debug++;                      break;
                case 'e': show_eeprom++;         break;
                case 'E': emergency_rewrite++;   break;
                case 'f': opt_f++; break;
                case 'F': new_default_media =3D get_media_index(optarg);
                        if (new_default_media < 0)
                                errflag++;
                        break;
                case 'g': opt_dma_diag++;       break;
                case 'G': opt_GPIO =3D strtol(optarg, NULL, 16); break;
                case 'H':
                        {
                                int hwaddr[6], i;
                                if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x",
                                                   hwaddr, hwaddr + 1, hwaddr + 2,
                                                   hwaddr + 3, hwaddr + 4, hwaddr + 5) 
=3D=3D 6) {
                                        for (i =3D 0; i < 6; i++)
                                                new_hwaddr[i] =3D hwaddr[i];
                                        set_hwaddr++;
                                } else
                                        errflag++;
                                break;
                        }
                case 'm': show_mii++;    break;
                case 'p':
                        port_base =3D strtol(optarg, NULL, 16);
                        break;
                case 'P': set_ee_rom++; break;
                case 'q': if (verbose) verbose--;                break;
                case 'r': opt_restart++;        break;
                case 'R': opt_reset++;          break;
                case 't': chip_type =3D atoi(optarg);   break;
                case 'v': verbose++;            break;
                case 'V': show_version++;       break;
                case 'w': do_write_eeprom++;    break;
                case 'W': opt_watch++;          break;
                        /* libflash only. */
                case 'B': opt_flash_show++;     break;
                case 'L': opt_flash_loadfile =3D optarg;        break;
                case 'S': opt_flash_dumpfile =3D optarg;        break;
                case '?':
                        errflag++;
                }
        if (errflag) {
                fprintf(stderr, usage_msg);
                return 3;
        }

        if (verbose || show_version)
                printf(version_msg);

        if (chip_type < 0
                || chip_type >=3D sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) {
                int i;
                fprintf(stderr, "Valid numeric chip types are:\n");
                for (i =3D 0; pcidev_tbl[i].part_name; i++) {
                        fprintf(stderr, "  %d\t%s\n", i, pcidev_tbl[i].part_name);
                }
                return 3;
        }

        /* Get access to all of I/O space. */
        if (iopl(3) < 0) {
                perror("vortex-diag: iopl()");
                fprintf(stderr, "This program must be run as root.\n");
                return 2;
        }

        /* Try to read a likely port_base value from /proc/pci. */
        if (port_base) {
                printf("Assuming a %s adapter at %#x.\n",
                           pcidev_tbl[chip_type].part_name, port_base);
                pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type);
        } else if ( scan_proc_pci(card_num) =3D=3D 0) {
                fprintf(stderr,
                                "Unable to find a recognized card in /proc/pci.\nIf 
there is"
                                " a card in the machine, explicitly set the I/O port"
                                " address\n  using '-p <ioaddr> -t 
<chip_type_index>'\n"
                                " Use '-t -1' to see the valid chip types.\n");
                return ENODEV;
        }

        if (show_regs =3D=3D 0  &&  show_eeprom =3D=3D 0  &&  show_mii =3D=3D 0)=

                printf(" Use '-a' or '-aa' to show device registers,\n"
                           "     '-e' to show EEPROM contents,\n"
                           "  or '-m' or '-mm' to show MII management registers.\n");

        return 0;
}

=0C
/* Generic (all PCI diags) code to find cards. */

static char bogus_iobase[] =3D
"This chip has not been assigned a valid I/O address, and will not functi=
on.\n"
" If you have warm-booted from another operating system, a complete \n"
" shut-down and power cycle may restore the card to normal operation.\n";=


static char bogus_irq[] =3D
"This chip has not been assigned a valid IRQ, and will not function.\n"
" This must be fixed in the PCI BIOS setup.  The device driver has no way=
\n"
" of changing the PCI IRQ settings.\n";

static int scan_proc_bus_pci(int card_num)
{
        int card_cnt =3D 0, chip_idx =3D 0;
        int port_base;
        char buffer[514];
        unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1;
        int i;
        FILE *fp =3D fopen("/proc/bus/pci/devices", "r");

        if (fp =3D=3D NULL) {
                if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n");
                return -1;
        }
        while (fgets(buffer, sizeof(buffer), fp)) {
                if (debug > 1)
                        fprintf(stderr, " Parsing line -- %s", buffer);
                if (sscanf(buffer, "%x %x %x %x %x",
                                   &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) 
<=3D 0)
                        break;
                for (i =3D 0; pcidev_tbl[i].vendor; i++) {
                        if (pci_devid !=3D
                                (pcidev_tbl[i].vendor << 16) + pcidev_tbl[i].device)
                                continue;
                        chip_idx =3D i;
                        card_cnt++;
                        port_base =3D pciaddr0 & ~1;
                        if (card_num =3D=3D 0 || card_num =3D=3D card_cnt) {
                                printf("Index #%d: Found a %s adapter at %#x.\n",
                                           card_cnt, pcidev_tbl[chip_idx].part_name,
                                           port_base);
                                if (irq =3D=3D 0  || irq =3D=3D 255)
                                        printf(bogus_irq);
                                if (port_base)
                                        pcidev_tbl[chip_idx].diag_func(0,0,port_base, 
i);
                                else
                                        printf(bogus_iobase);
                                break;
                        }
                }
        }
        fclose(fp);
        return card_cnt;
}

static int scan_proc_pci(int card_num)
{
        int card_cnt =3D 0, chip_idx =3D 0;
        char chip_name[40];
        FILE *fp;
        int port_base;

        if ((card_cnt =3D scan_proc_bus_pci(card_num)) >=3D 0)
                return card_cnt;
        card_cnt =3D 0;

        fp =3D fopen("/proc/pci", "r");
        if (fp =3D=3D NULL)
                return 0;
        {
                char buffer[514];
                int pci_bus, pci_device, pci_function, vendor_id, device_id;
                int state =3D 0;
                if (debug) printf("Done open of /proc/pci.\n");
                while (fgets(buffer, sizeof(buffer), fp)) {
                        if (debug > 1)
                                fprintf(stderr, " Parse state %d line -- %s", state, 
buffer);
                        if (sscanf(buffer, " Bus %d, device %d, function %d",
                                           &pci_bus, &pci_device, &pci_function) > 0) {
                                chip_idx =3D 0;
                                state =3D 1;
                                continue;
                        }
                        if (state =3D=3D 1) {
                                if (sscanf(buffer, " Ethernet controller: %39[^\n]",
                                                   chip_name) > 0) {
                                        int i;
                                        if (debug)
                                                printf("Named ethernet controller 
%s.\n", chip_name);
                                        for (i =3D 0; pcidev_tbl[i].proc_pci_name; i++)
                                                if 
(strncmp(pcidev_tbl[i].proc_pci_name, chip_name,
                                                                        
strlen(pcidev_tbl[i].proc_pci_name))
                                                        =3D=3D 0) {
                                                        state =3D 2;
                                                        chip_idx =3D i;
                                                        continue;
                                                }
                                        continue;
                                }
                                /* Handle a /proc/pci that does not recognize the 
card. */
                                if (sscanf(buffer, " Vendor id=3D%x. Device id=3D%x",
                                                   &vendor_id, &device_id) > 0) {
                                        int i;
                                        if (debug)
                                                printf("Found vendor 0x%4.4x device ID 
0x%4.4x.\n",
                                                           vendor_id, device_id);
                                        for (i =3D 0; pcidev_tbl[i].vendor; i++)
                                                if (vendor_id =3D=3D 
pcidev_tbl[i].vendor  &&
                                                        (device_id & 
pcidev_tbl[i].device_mask)
                                                        =3D=3D pcidev_tbl[i].device)
                                                        break;
                                        if (pcidev_tbl[i].vendor =3D=3D 0)
                                                continue;
                                        chip_idx =3D i;
                                        state =3D 2;
                                }
                        }
                        if (state =3D=3D 2) {
                                if (sscanf(buffer, "  I/O at %x", &port_base) > 0) {
                                        card_cnt++;
                                        state =3D 3;
                                        if (card_num =3D=3D 0 || card_num =3D=3D 
card_cnt) {
                                                printf("Index #%d: Found a %s adapter 
at %#x.\n",
                                                           card_cnt, 
pcidev_tbl[chip_idx].part_name,
                                                           port_base);
                                                if (port_base)
                                                        pcidev_tbl[chip_idx].diag_func
                                                                (vendor_id, device_id, 
port_base, chip_idx);
                                                else
                                                        printf(bogus_iobase);
                                        }
                                }
                        }
                }
        }
        fclose(fp);
        return card_cnt;
}

/* Convert a text media name to a NWay capability word. */
static int parse_media_type(const char *capabilities)
{
        const char *mtypes[] =3D {
                "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD",
                "10baseT", "10baseT-FD", "10baseT-HD", 0,
        };
        int cap_map[] =3D { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x00=
20,};
        int i;
        if (debug)
                fprintf(stderr, "Advertise string is '%s'.\n", capabilities);
        for (i =3D 0; mtypes[i]; i++)
                if (strcmp(mtypes[i], capabilities) =3D=3D 0)
                        return cap_map[i];
        if ((i =3D strtol(capabilities, NULL, 16)) <=3D 0xffff)
                return i;
        fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities);
        return 0;
}

/* Return the index of a valid media name.
   0x0800       Power up autosense (check speed only once)
   0x8000       Dynamic Autosense
*/
/* A table of names to indices. */
struct { char *name; int value; } mediamap[] =3D {
        { "10baseT", 0 },
        { "10base2", 1 },
        { "AUI", 2 },
        { "100baseTx", 3 },
        { "10baseT-FDX", 4 },
        { "100baseTx-FDX", 5 },
        { "100baseT4", 6 },
        { "100baseFx", 7 },
        { "100baseFx-FDX", 8 },
        { "MII", 11 },
        { "Autosense", 0x0800 },
        { 0, 0 },
};

static int get_media_index(const char *name)
{
        int i;
        for (i =3D 0; mediamap[i].name; i++)
                if (strcmp(name, mediamap[i].name) =3D=3D 0)
                        return i;
        if (name)
                return atoi(name);
        fprintf(stderr, "Invalid interface specified: it must be one of\n  ");
        for (i =3D 0; mediamap[i].name; i++)
                fprintf(stderr, "  %s", mediamap[i].name);
        fprintf(stderr, ".\n");
        return -1;
}

=0C
/* Chip-specific section. */

/* The 3Com Vortex/Boomerang/Cyclone designs. */
static int read_eeprom(int ioaddr, int addrsize, int location);
static void write_eeprom(int ioaddr, int addrsize, int index, int value);=

static int do_update(int ioaddr, int addrlen, =

                                         unsigned short *ee_values, unsigned short 
*old_ee_values);
static void mdio_sync(int ioaddr);
int mdio_read(int ioaddr, int phy_id, int location);
void mdio_write(int ioaddr, int phy_id, int location, int value);

static void parse_eeprom(unsigned short *ee_data);
static void show_dma_state(long ioaddr);


#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CM=
D)
#define EL3_CMD 0x0e

enum vortex_cmd {
        TotalReset =3D 0<<11, SelectWindow =3D 1<<11, StartCoax =3D 2<<11,
        RxDisable =3D 3<<11, RxEnable =3D 4<<11, RxReset =3D 5<<11,
        UpStall =3D 6<<11, UpUnstall =3D (6<<11)+1,
        DownStall =3D (6<<11)+2, DownUnstall =3D (6<<11)+3,
        RxDiscard =3D 8<<11, TxEnable =3D 9<<11, TxDisable =3D 10<<11, TxReset =3D=
 11<<11,
        FakeIntr =3D 12<<11, AckIntr =3D 13<<11, SetIntrEnb =3D 14<<11,
        SetStatusEnb =3D 15<<11, SetRxFilter =3D 16<<11, SetRxThreshold =3D 17<<=
11,
        SetTxThreshold =3D 18<<11, SetTxStart =3D 19<<11,
        StartDMAUp =3D 20<<11, StartDMADown =3D (20<<11)+1, StatsEnable =3D 21<<=
11,
        StatsDisable =3D 22<<11, StopCoax =3D 23<<11,};

/* Bits in the general status register. */
enum vortex_status {
        IntLatch =3D 0x0001, AdapterFailure =3D 0x0002, TxComplete =3D 0x0004,
        TxAvailable =3D 0x0008, RxComplete =3D 0x0010, RxEarly =3D 0x0020,
        IntReq =3D 0x0040, StatsFull =3D 0x0080,
        DMADone =3D 1<<8, DownComplete =3D 1<<9, UpComplete =3D 1<<10,
        DMAInProgress =3D 1<<11,                        /* DMA controller is still 
busy.*/
        CmdInProgress =3D 1<<12,                        /* EL3_CMD is still busy.*/
};
const char *intr_names[13] =3D{
        "Interrupt latch", "Adapter Failure", "Tx Complete", "Tx Available",
        "Rx Complete", "Rx Early Notice", "Driver Intr Request",
        "Statistics Full", "DMA Done", "Download Complete", "Upload Complete",
        "DMA in Progress", "Command in Progress",
};

enum Window0 {
        Wn0EepromCmd =3D 10,            /* Window 0: EEPROM command register. */
        Wn0EepromData =3D 12,           /* Window 0: EEPROM results register. */
        IntrStatus=3D0x0E,                      /* Valid in all windows. */
};
#define MAX_EEPROM_SIZE 256
/* In undocumented bogusness, these value depend on the EEPROM size. */
enum Win0_EEPROM_cmds {
        EEPROM_Read =3D 2, EEPROM_WRITE =3D 1, EEPROM_ERASE =3D 3,
        EEPROM_EWENB =3D 0xC,           /* Enable erasing/writing for 10 msec. */
        EEPROM_EWDIS =3D 0x0,           /* Disable EWENB before 10 msec timeout. */
};

enum Window3 {                  /* Window 3: MAC/config bits. */
        Wn3_Config=3D0, Wn3_MaxPktSz=3D4, Wn3_MAC_Ctrl=3D6, Wn3_Options=3D8,
};
enum Window4 {          /* Window 4: Xcvr/media bits. */
        Wn4_FIFODiag =3D 4, Wn4_NetDiag =3D 6, Wn4_PhysicalMgmt=3D8, Wn4_Media =3D=
 10,
};
/* Media names in Wn3_Config bits 24:20. */
const char *el_medianames[16] =3D{
        "10baseT", "10Mbs AUI", "undefined", "10base2",
        "100baseTX", "100baseFX", "MII", "undefined",
        "Autonegotiate", "MII-External", "undefined-10", "undefined-11",
        "undefined-12", "undefined-13", "undefined-14", "undefined-15",
};

/* Values read from the EEPROM, and the new image. */
unsigned short eeprom_contents[MAX_EEPROM_SIZE];
unsigned short new_ee_contents[MAX_EEPROM_SIZE];

int vortex_diag(int vendor_id, int dev_id, int ioaddr, int part_idx)
{
        int chip_active =3D 0;
        int saved_window =3D inw(ioaddr + EL3_CMD) >> 13;
        int internal_config;
        int eeaddrlen, eesize;
        int i;

        /* It's mostly safe to examine the registers and EEPROM during
           operation.  But warn the user, and make then pass '-f'. */
#ifdef notdef
        if ((inl(ioaddr + EL3_CMD) & 0xE000) =3D=3D 0xE000)
                chip_active =3D 1;
#endif

        if (opt_a) {
                int io_size =3D pcidev_tbl[part_idx].io_size;
                int j;

                if (!opt_f) {
                        printf("The Vortex chip may be active, so FIFO registers"
                                   " will not be read.\n"
                                   "To see all register values use the '-f' flag.\n");
                } else
                        chip_active =3D 0;              /* Ignore the chip status with 
-f */

                printf("Initial window %d, registers values by window:\n",
                           saved_window);
                for (j =3D 0; j < 8; j++) {
                        printf("  Window %d:", j);
                        outw(SelectWindow + j, ioaddr + EL3_CMD);
                        for (i =3D 0; i < 16; i+=3D2) {
                                if (j =3D=3D 1 && i < 4 && ! opt_f)
                                        printf(" FIFO");
                                else
                                        printf(" %4.4x", inw(ioaddr + i));
                        }
                        printf(".\n");
                }
                printf("Vortex chip registers at %#x", ioaddr);
                for (i =3D 0x10;
                         i < (io_size > 0x40 ? 0x40 : io_size);
                         i +=3D 4) {
                        if ((i & 0x0f) =3D=3D 0)
                                printf("\n  0x%3.3X:", ioaddr + i);
                        if (! opt_f) {
                                if (i =3D=3D 0x10)
                                        printf(" **FIFO**");
                                else if (i =3D=3D 0x1c)
                                        printf(" *STATUS*");
                                else
                                        printf(" %8.8x", inl(ioaddr + i));
                        } else
                                printf(" %8.8x", inl(ioaddr + i));
                }
                printf("\n");
        }
        if (opt_dma_diag)
                show_dma_state(ioaddr);
        EL3WINDOW(3);
        internal_config =3D inl(ioaddr + Wn3_Config);
        if (verbose > 1 || opt_a) {
                unsigned intr_status =3D inw(ioaddr + IntrStatus);
                EL3WINDOW(5);
                printf(" Indication enable is %4.4x, interrupt enable is %4.4x.\n",
                           inw(ioaddr + 12), inw(ioaddr + 10));
                printf(" %snterrupt sources are pending.\n",
                           (intr_status & 0x03ff) ? "I": "No i");
                if (intr_status) {
                        for (i =3D 0; i < 13; i++)
                                if (intr_status & (1<<i))
                                        printf("   %s indication.\n", intr_names[i]);
                }
                {
                        const char *medias[] =3D {"100baseT4", "100baseTx", 
"100baseFx",
                        "10baseT", "10base2", "AUI", "MII", "", "10baseFL"};
                        int MediaOptions, MacCtrl;
                        EL3WINDOW(3);
                        MediaOptions =3D inw(ioaddr + Wn3_Options);
                        printf(" Transceiver/media interfaces available: ");
                        for (i =3D 0; i < 8; i++)
                                if (MediaOptions & 1<<i)
                                        printf(" %s", medias[i]);
                        printf("%s.\n", (MediaOptions&0xE010)=3D=3D0x0010 ? "10baseFL" 
: "");
                        printf("Transceiver type in use:  %s.\n",
                                   el_medianames[(internal_config >> 20) & 15]);
                        MacCtrl =3D inw(ioaddr + Wn3_MAC_Ctrl);
                        printf(" MAC settings: %s-duplex%s%s%s.\n",
                                   MacCtrl & 0x020 ? "full":"half",
                                   MacCtrl & 0x040 ? ", Large packets permitted":"",
                                   MacCtrl & 0x100 ? ", 802.1Q flow control":"",
                                   MacCtrl & 0x200 ? ", VLT VLAN enabled":"");
                        if (inw(ioaddr + Wn3_MaxPktSz) !=3D 1514)
                                printf("Maximum packet size is %d.\n",
                                           inw(ioaddr + Wn3_MaxPktSz));
                }
                EL3WINDOW(2);
                printf(" Station address set to 
%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n"=
,
                           inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
                           inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5));
                /* This register only exists on certain Cyclone chips. */
                printf(" Configuration options %4.4x.\n", inw(ioaddr + 14));
        }
        /* Read the EEPROM. */
        EL3WINDOW(0);

        outw(0x5555, ioaddr + Wn0EepromData);
        if (read_eeprom(ioaddr, 6, 0) !=3D 0x5555) {
                if (debug)
                        printf(" EEPROM Address length is 6 bits (%4.4x).\n",
                                   read_eeprom(ioaddr, 6, 0));
                eeaddrlen =3D 6;
        } else {
                int val =3D read_eeprom(ioaddr, 6, 0);
                int e6 =3D read_eeprom(ioaddr, 6, 0);
                int e8 =3D read_eeprom(ioaddr, 8, 0);
                if (1 || debug)
                        printf(" EEPROM address sizing read returned 
%4.4x/%4.4x/%4.4x.\n",
                                   e6, e8, val);
                eeaddrlen =3D (e6 !=3D 0xffff) ? 8 : 6;
        }
        eesize =3D 1 << eeaddrlen;

        if (debug)
                printf(" EEPROM address size is %d bits.\n", eeaddrlen);
        for (i =3D 0; i < eesize; i++)
                eeprom_contents[i] =3D read_eeprom(ioaddr, eeaddrlen, i);

        if (set_hwaddr) {
                unsigned short sum =3D 0;
                memcpy(new_ee_contents, eeprom_contents, eesize << 1);
                for (i =3D 0; i < 3; i++)
                        new_ee_contents[i + 10] =3D (new_hwaddr[i*2]<<8) + 
new_hwaddr[i*2+1];
                /* Recalculate the checksum: Cyclone only! */
                for (i =3D 0; i < 0x1A; i++)
                        sum ^=3D new_ee_contents[i];
                new_ee_contents[0x20] =3D (sum ^ (sum>>8)) & 0xff;
                do_update(ioaddr, eeaddrlen, new_ee_contents, eeprom_contents);
                for (i =3D 0; i < eesize; i++)
                        eeprom_contents[i] =3D read_eeprom(ioaddr, eeaddrlen, i);
        }

        if (set_ee_rom) {
                unsigned short sum =3D 0;
                memcpy(new_ee_contents, eeprom_contents, eesize << 1);
                new_ee_contents[9] =3D 0x3001;
                /* Recalculate the checksum: Cyclone only! */
                for (i =3D 0; i < 0x1B; i++)
                        sum ^=3D new_ee_contents[i];
                new_ee_contents[0x20] =3D (sum ^ (sum>>8)) & 0xff;
                printf("Setting the EEPROM BIOS ROM field to %4.4x, new checksum "
                           "%2.2x.\n", new_ee_contents[9], new_ee_contents[0x20]);
                do_update(ioaddr, eeaddrlen, new_ee_contents, eeprom_contents);
                for (i =3D 0; i < eesize; i++)
                        eeprom_contents[i] =3D read_eeprom(ioaddr, eeaddrlen, i);
        }
        if (verbose + show_eeprom > 2) {
                unsigned short sum =3D 0;
                printf("EEPROM contents (%d words):", eesize);
                for (i =3D 0; i < eesize; i++) {
                        if (i % 8 =3D=3D 0)
                                printf("\n 0x%3.3x:", i);
                        printf(" %4.4x", eeprom_contents[i]);
                        sum +=3D eeprom_contents[i];
                }
                printf("\n The word-wide EEPROM checksum is %#4.4x.\n", sum);
        }

        /* The user will usually want to see the interpreted EEPROM contents. */=

        if (verbose > 1 || show_eeprom) {
                parse_eeprom(eeprom_contents);
        }

        /* Show up to four (not just the on-board) PHYs. */
        if (verbose > 1 || show_mii) {
                int phys[4], phy, phy_idx =3D 0;
                int mii_reg;
                int saved_media_options;
                phys[0] =3D 24;                 /* Default for most 3Com products. */
                EL3WINDOW(3);
                /* Turn on the MII transceiver for some cards. */
                saved_media_options =3D inw(ioaddr + Wn3_Options);
                outw((saved_media_options & 0x1ff) | 0x8000, ioaddr + Wn3_Options);

                EL3WINDOW(4);
                mdio_sync(ioaddr);
                for (phy =3D 1; phy <=3D 32 && phy_idx < 4; phy++) {
                        int mii_status =3D mdio_read(ioaddr, phy & 0x1f, 1);
                        if (mii_status !=3D 0xffff  &&  mii_status !=3D 0) {
                                phys[phy_idx++] =3D phy&0x1f;
                                printf(" MII PHY found at address %d, status %4.4x.\n",
                                           phy & 0x1f, mii_status);
                        }
                }
                if (phy_idx =3D=3D 0)
                        printf(" ***WARNING***: No MII transceivers found!\n");
                for (phy =3D 0; phy < phy_idx; phy++) {
                        printf(" MII PHY %d at #%d transceiver registers:",
                                   phy, phys[phy]);
                        for (mii_reg =3D 0; mii_reg < 32; mii_reg++)
                                printf("%s %4.4x", (mii_reg % 8) =3D=3D 0 ? "\n  " : 
"",
                                           mdio_read(ioaddr, phys[phy], mii_reg));
                        printf(".\n");
                }
                if (opt_reset) {
                        printf("Resetting the transceiver...\n");
                        mdio_write(ioaddr, phys[phy], 0, 0x8000);
                }
                if (phy_idx  &&  nway_advertise > 0) {
                        printf(" Setting the media capability advertisement register 
of "
                                   "PHY #%d to 0x%4.4x.\n", phys[0], nway_advertise | 
1);
                        mdio_write(ioaddr, phys[0], 4, nway_advertise | 1);
                }
                if (opt_restart) {
                        printf("Restarting negotiation...\n");
                        mdio_write(ioaddr, phys[0], 0, 0x0000);
                        mdio_write(ioaddr, phys[0], 0, 0x1200);
                }
                /* To force 100baseTx-HD do  mdio_write(ioaddr, phys[0], 0, 0x2000); 
*/=

                if (fixed_speed >=3D 0) {
                        int reg0_val =3D 0;
                        reg0_val |=3D (fixed_speed & 0x0180) ? 0x2000 : 0;
                        reg0_val |=3D (fixed_speed & 0x0140) ? 0x0100 : 0;
                        printf("Setting the speed to \"fixed\", %4.4x.\n", reg0_val);
                        mdio_write(ioaddr, phys[0], 0, reg0_val);
                }

#ifdef LIBMII
                if (show_mii > 1)
                        show_mii_details(ioaddr, phys[0]);
                if (opt_watch || show_mii > 2)
                        monitor_mii(ioaddr, phys[0]);
#endif
                EL3WINDOW(3);
                outw(saved_media_options, ioaddr + Wn3_Options);
        }

#ifdef LIBFLASH
        /* First, work around a chip buglet: the media must be set to EXT MII
           to read the flash on one Hurricane rev. */
        /* Turn on the MII transceiver for some cards. */
        {
                if (pcidev_tbl[part_idx].flags & HAS_FLASH_BUG) {
                        EL3WINDOW(3);
                        outl((internal_config & ~0xf00000)|0x800000, ioaddr + 
Wn3_Config);
                }
                EL3WINDOW(0);
                if (opt_flash_show)
                        flash_show(ioaddr + 4, ioaddr + 8);
                if (opt_flash_dumpfile)
                        if (flash_dump(ioaddr + 4, ioaddr + 8, opt_flash_dumpfile) < 
0) {
                                fprintf(stderr, "Failed to save the old Flash BootROM 
image "
                                                "into file '%s'.\n", 
opt_flash_dumpfile);
                                EL3WINDOW(3);
                                outl(internal_config, ioaddr + Wn3_Config);
                                EL3WINDOW(saved_window);
                                return 3;
                        }
                if (opt_flash_loadfile)
                        if (flash_program(ioaddr+4, ioaddr+8, opt_flash_loadfile) < 0) 
{
                                fprintf(stderr, "Failed to load the new Flash BootROM 
image "
                                                "from file '%s'.\n", 
opt_flash_loadfile);
                                EL3WINDOW(3);
                                outl(internal_config, ioaddr + Wn3_Config);
                                EL3WINDOW(saved_window);
                                return 4;
                        }
                if (HAS_FLASH_BUG) {
                        EL3WINDOW(3);
                        outl(internal_config, ioaddr + Wn3_Config);
                }
        }
#else
        if (opt_flash_loadfile  || opt_flash_dumpfile  ||  opt_flash_show)
                printf("Flash operations not configured into this program.\n");
#endif

        if (do_test) {
                int bogus_cnt =3D 10000;
                /* Run the built-in-self-test of the SRAM buffer.  This is
                   valid only on the boomerang, but we run it unconditionally. */
                EL3WINDOW(4);
                outw(0x0004, ioaddr + Wn4_FIFODiag);
                while ((inw(ioaddr + Wn4_FIFODiag) & 0x0020) =3D=3D 0  &&  --bogus_cnt 
=
> 0)
                        inw(ioaddr + Wn4_FIFODiag);
                if (inw(ioaddr + Wn4_FIFODiag) & 0x0020)
                        printf("SRAM buffer test %s\n",
                                   inw(ioaddr + Wn4_FIFODiag) & 0x0010 ? "failed!" : 
"passed");
                else
                        printf("INTERNAL FAILURE -- SRAM buffer test did not 
complete!\n");
        }
        EL3WINDOW(saved_window);
        return 0;
}

=0C
/* Serial EEPROM section. */
static int read_eeprom(int ioaddr, int addrlen, int location)
{
        int timer;

        outw((2 << addrlen) + location, ioaddr + Wn0EepromCmd);
        /* Wait for the read to take place, worst-case 162 us. */
        for (timer =3D 1620; timer >=3D 0; timer--) {
                if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) =3D=3D 0)
                        break;
        }
        if (debug > 2)
                fprintf(stderr, "  EEPROM read completed in %d ticks, %4.4x.\n",
                                1620-timer, inw(ioaddr + Wn0EepromData));
        return inw(ioaddr + Wn0EepromData);
}

static void write_eeprom(int ioaddr, int addrlen, int index, int value)
{
        int timer;
        /* Verify that the EEPROM is idle. */
        for (timer =3D 1620; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
                if (--timer < 0)
                        goto error_return;
        /* Enable writing. */
        outw(3 << (addrlen-2), ioaddr + Wn0EepromCmd);
        for (timer =3D 400; inw(ioaddr + Wn0EepromCmd) & 0x8000;) {
                if (--timer < 0)
                        goto error_return;
        }
        if (debug)
                fprintf(stderr, "EEPROM write enable took %d ticks!\n", 400 - timer);
        outw((EEPROM_ERASE << addrlen) + index, ioaddr + Wn0EepromCmd);
        for (timer =3D 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
                if (--timer < 0) {
                        fprintf(stderr, "EEPROM failed to erase index %d!\n", index);
                        return;
                }
        if (debug)
                fprintf(stderr, "EEPROM erased index %d after %d ticks!\n",
                                index, 16000-timer);
        outw(3 << (addrlen-2), ioaddr + Wn0EepromCmd);
        for (timer =3D 400; inw(ioaddr + Wn0EepromCmd) & 0x8000;) {
                if (--timer < 0)
                        goto error_return;
        }
        if (debug)
                fprintf(stderr, "EEPROM write enable took %d ticks!\n", 400-timer);
        outw(value, ioaddr + Wn0EepromData);
        outw((EEPROM_WRITE << addrlen) + index, ioaddr + Wn0EepromCmd);
        for (timer =3D 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
                if (--timer < 0)
                        goto error_return;
        if (debug)
                fprintf(stderr, "EEPROM wrote index %d with 0x%4.4x after %d 
ticks!\n",=

                                index, value, 16000-timer);
        return;
error_return:
        fprintf(stderr, "Failed to write EEPROM location %d with 0x%4.4x!\n",
                        index, value);
}

static int do_update(int ioaddr, int addrlen, =

                                         unsigned short *ee_values, unsigned short 
*old_ee_values)
{
        int i;

        EL3WINDOW(0);
        if (debug)
                printf("Comparing %d words (address length %d) in do_update().\n",
                           1<<addrlen, addrlen);
        for (i =3D 0; i < (1<<addrlen); i++) {
                if (ee_values[i] !=3D old_ee_values[i]) {
                        if (do_write_eeprom) {
                                if (verbose)
                                        printf("Writing an EEPROM word offset %d value 
0x%4.4x.\n",
                                                   i, ee_values[i]);
                                write_eeprom(ioaddr, addrlen, i, ee_values[i]);
                        } else
                                printf(" Would write new %d entry 0x%4.4x (old value 
0x%4.4x).\n", =

                                           i, ee_values[i], old_ee_values[i]);
                }
        }
        outw(EEPROM_EWDIS << addrlen, ioaddr + Wn0EepromCmd);
        for (i =3D 400; i > 0 && inw(ioaddr + Wn0EepromCmd) & 0x8000; i--)
                ;
        return 0;
}
=0C

/* Read and write the MII registers using software-generated serial
   MDIO protocol.  It is just different enough from the EEPROM protocol
   to not share code.  The maxium data clock rate is 2.5 Mhz, which is me=
t
   by the PCI I/O access timing. */
#define mdio_delay(mdio_addr)   inw(mdio_addr)

#define MDIO_SHIFT_CLK  0x01
#define MDIO_DIR_WRITE  0x04
#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
#define MDIO_DATA_READ  0x02
#define MDIO_ENB_IN             0x00

static int mii_preamble_required =3D 1;
static void mdio_sync(int ioaddr)
{
        int mdio_addr =3D ioaddr + Wn4_PhysicalMgmt;
        int i;
        /* Establish sync by sending at least 32 logic ones. */ =

        for (i =3D 32; i >=3D 0; i--) {
                outw(MDIO_DATA_WRITE1, mdio_addr);
                mdio_delay(mdio_addr);
                outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay(mdio_addr);
        }
}
int mdio_read(int ioaddr, int phy_id, int location)
{
        int i;
        int read_cmd =3D (0xf6 << 10) | (phy_id << 5) | location;
        unsigned int retval =3D 0;
        int mdio_addr =3D ioaddr + Wn4_PhysicalMgmt;

        if (verbose > 2)                /* Debug: 5 */
                printf(" mdio_read(%#x, %d, %d)..", ioaddr, phy_id, location);
        if (mii_preamble_required)
                mdio_sync(ioaddr);
        /* Shift the read command bits out. */
        for (i =3D 14; i >=3D 0; i--) {
                int dataval =3D (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : 
MDIO_DATA_WRITE0=
;
                if (verbose > 3)                /* Debug: 5 */
                        printf("%d", (read_cmd & (1 << i)) ? 1 : 0);

                outw(dataval, mdio_addr);
                mdio_delay(mdio_addr);
                outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
                if (verbose > 3) printf(" %x", (inw(mdio_addr) >> 16) & 0x0f);
                mdio_delay(mdio_addr);
        }
        if (verbose > 3) printf("-> %x", (inw(mdio_addr) >> 16) & 0x0f);

        if (verbose > 3)                /* Debug: 5 */
                printf(" \n");

        /* Read the two transition, 16 data, and wire-idle bits. */
        for (i =3D 19; i > 0; i--) {
                outw(MDIO_ENB_IN, mdio_addr);
                mdio_delay(mdio_addr);
                retval =3D (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 
0);=

                outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay(mdio_addr);
                if (verbose > 3) printf(" %x", (inw(mdio_addr) >> 16) & 0x0f);
        }
        if (verbose > 2)                /* Debug: 5 */
                printf(" %4.4x.\n", retval);

        /* Avoid buggy 3c905B MDIO implementation. */
        return (retval & 0x20000) =3D=3D 0x00000 ? retval>>1 & 0x1ffff : 0;
}

void mdio_write(int ioaddr, int phy_id, int location, int value)
{
        int write_cmd =3D 0x50020000 | (phy_id << 23) | (location << 18) | value=
;
        int mdio_addr =3D ioaddr + Wn4_PhysicalMgmt;
        int i;

        if (verbose > 2)                /* Debug: 5 */
                printf(" mdio_write(%#x, %d, %d, %4.4x)..",
                           ioaddr, phy_id, location, value);
        if (mii_preamble_required)
                mdio_sync(ioaddr);

        /* Shift the command bits out. */
        for (i =3D 31; i >=3D 0; i--) {
                int dataval =3D (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : 
MDIO_DATA_WRITE=
0;
                outw(dataval, mdio_addr);
                mdio_delay(mdio_addr);
                outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay(mdio_addr);
        }
        /* Leave the interface idle. */
        for (i =3D 1; i >=3D 0; i--) {
                outw(MDIO_ENB_IN, mdio_addr);
                mdio_delay(mdio_addr);
                outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay(mdio_addr);
        }

        return;
}

=0C
static void parse_eeprom(unsigned short *eeprom)
{
        unsigned char *p =3D (void *)eeprom;
        u16 *ee =3D eeprom;
        int i, sum =3D 0;

        printf("Parsing the EEPROM of a 3Com Vortex/Boomerang:\n");
        if (eeprom[0] =3D=3D 0x10b7) {
                printf(" The CardBus product ID is %4.4x %4.4x.\n",
                           eeprom[0], eeprom[1]);
                p +=3D 0x60;
                ee +=3D 0x30;
        }
        printf(" 3Com Node Address ");
        for (i =3D 0; i < 5; i++)
                printf("%2.2X:", p[i^1]);
        printf("%2.2X (used as a unique ID only).\n", p[i^1]);
        printf(" OEM Station address %2.2x", p[1 + 20]);
        for (i =3D 1; i < 6; i++)
                printf(":%2.2X", p[(i^1) + 20]);
        printf(" (used as the ethernet address).\n");
        printf(" Manufacture date (MM/DD/YYYY) %d/%d/%d, division %c,"
                   " product %c%c.\n", ((p[8]>>5) & 7) + ((p[9]<<3) & 8),
                   p[8] & 31, (p[9]>>1) + 1900, p[10], p[12], p[13]);
        printf("Options: %s.\n",
                   ee[13] & 0x8000 ? "force full-duplex" : "none");
        for (i =3D 0; i < 0x16; i++)
                sum ^=3D ee[i];
        printf("  Vortex format checksum is %scorrect (%4.4x vs. %4.4x).\n",
                   ((sum ^ (sum>>8)) & 0xff) =3D=3D ee[0x17] ? "" : "in",
                   (sum ^ (sum>>8)) & 0xff, ee[0x17]);
        for ( ; i < 0x1A; i++)
                sum ^=3D ee[i];
        sum ^=3D sum>>8;
        printf("  Cyclone format checksum is %scorrect (%#2.2x vs. %#2.2x).\n",
                   (sum  & 0xff) =3D=3D (ee[0x20] & 0xff) ? "" : "in",
                   sum & 0xff, ee[0x20] & 0xff);
        for (sum =3D 0, i =3D 0; i < 0x20*2; i++)
                sum ^=3D ((unsigned char *)ee)[i];
        printf("  Hurricane format checksum is %scorrect (%#2.2x vs. %#2.2x).\n"=
,
                   sum =3D=3D (ee[0x20] & 0xff) ? "" : "in",
                   sum, ee[0x20] & 0xff);
        return;
}
=0C
static void show_dma_state(long ioaddr)
{
        int dma_ctrl =3D inl(ioaddr + 0x20);
        printf("  DMA control register is %8.8x.\n", dma_ctrl);
        if (dma_ctrl & 0x0080) {
                outw(DownStall, ioaddr + EL3_CMD);
                printf("   DMA control register is %8.8x (during Tx Stall).\n",
                           inl(ioaddr + 0x20));
                outw(DownUnstall, ioaddr + EL3_CMD);
        }
        printf("   Tx list starts at %8.8x.\n",
                   inl(ioaddr + 0x24));
        printf("   Tx FIFO thresholds: min. burst %d bytes, "
                   "priority with %d bytes to empty.\n",
                   inb(ioaddr + 0x2A)<<5, inl(ioaddr + 0x2C)<<5);
        printf("   Tx poll period %d0 ns.\n",
                   inb(ioaddr + 0x2D)<<5);
        printf("   Tx maximum burst recorded %d.\n",
                   inw(ioaddr + 0x78));
}

=0C
/*
 * Local variables:
 *  compile-command: "cc -O -Wall -o vortex-diag vortex-diag.c -DLIBMII l=
ibmii.c"
 *  alt-compile-command: "cc -O -Wall -o vortex-diag vortex-diag.c"
 *  flash-compile-command: "cc -O -Wall -o vortex-diag vortex-diag.c -DLI=
BMII libmii.c  -DLIBFLASH libflash.c"
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 * End:
 */

==============F353063F8B284B69DF864337==


------------------------------


** FOR YOUR REFERENCE **

The service address, to which questions about the list itself and requests
to be added to or deleted from it should be directed, is:

    Internet: [EMAIL PROTECTED]

You can send mail to the entire list (and comp.os.linux.hardware) via:

    Internet: [EMAIL PROTECTED]

Linux may be obtained via one of these FTP sites:
    ftp.funet.fi                                pub/Linux
    tsx-11.mit.edu                              pub/linux
    sunsite.unc.edu                             pub/Linux

End of Linux-Hardware Digest
******************************

Reply via email to