Last Netgear’s FA410TX pcmcia ethernet card and FreeBSD 4.x

Last Netgear’s FA410TX pcmcia ethernet card and FreeBSD 4.x

Last Netgear’s FA410TXC cards use a new chipset, so there are detection
and initialisation problems with these cards under FreeBSD.

The symptoms

  1. Bad MAC address detection under 4.0-Release: the MAC address saw by freebsd is different
    from the one written on the card (it’s fixed under 4.1-Release).
  2. device timeout messages like ‘ed0: device timeout’.

The solution

  1. Correct card detection (for 4.0-R only):

    The card MAC address is written on the card
    (Node ID), mine is 00 E0 98 7A F5 61. By default the ed driver doesn’t detect the good
    type of card and so the correct MAC address.

    To fix that we need to modify /usr/src/sys/dev/ed/if_ed.c at line 1016 we’ve got this:

        if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) {
        /* could be either an NE1000 or a Linksys ethernet controller */
            linksys = ed_get_Linksys(sc);

    replace with:

        /* 
        if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) {
        */
        if (1) {
        /* could be either an NE1000 or a Linksys ethernet controller */
            linksys = ed_get_Linksys(sc);
        

    Rebuild your kernel and reboot, now your card must be detected with correct address and
    type Linksys (16).

  2. Force speed negociation:

    The card seems unable to negociate link. I modified the
    fa_select.c used under linux to fix that problem.

    Here’s the code for FreeBSD:

    
    /* fa_select.c                  */
    /* modified for FreeBSD 4.x     */
    /*                              */
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <net/if.h>
    #include <stdio.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <machine/sysarch.h>
    
    #define BASE_ADDR      0x240 /* replace with the card base address */
    
    inline unsigned char
    inb (unsigned short port)
    {
        unsigned char _v;
        
        __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (port));
        return _v;
    }
    
    inline void
    outb (unsigned char value, unsigned short port)
    {
        __asm__ __volatile__ ("outb %b0,%w1"::"a" (value), "Nd" (port));
    }
    
    static int sockets_open(void)
    {
        int sock;
        if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) != -1)
            return sock;
        else if ((sock = socket(AF_IPX, SOCK_DGRAM, 0)) != -1)
            return sock;
        else
            return socket(AF_APPLETALK, SOCK_DGRAM, 0);
    }
    void write_bit(int port, int bit)
    {
    outb((bit << 6) + 0x20, port);
        usleep(1);
        outb((bit << 6) + 0xa0, port);
        usleep(1);
        outb((bit << 6) + 0x20, port);
    }
    int read_bit(int port)
    {
        int i;
        outb(0,    port);
        usleep(1);
        outb(0x80, port);
        usleep(1);
        i = inb(port);
        outb(0,    port);
        return (i & 0x10) >> 4;
    }
    void reset(int port)
    {
        outb(0x08, port);
        usleep(1);
        outb(0x0C, port);
        usleep(1);
        outb(0x08, port);
        usleep(1);
        outb(0x0C, port);
        outb(0x00, port);
    }
    int reada(int port, int adr)
    {
        int i,j;
        
        for (i=0; i<0x20; i++)
            write_bit(port, 1);
        
        write_bit(port, 0);
        write_bit(port, 1);
        write_bit(port, 1);
        write_bit(port, 0);
        
        write_bit(port, 0);
        write_bit(port, 0);
        write_bit(port, 0);
        write_bit(port, 0);
        write_bit(port, 0);
        
        write_bit(port, (adr & 0x10) >> 4);
        write_bit(port, (adr & 0x08) >> 3);
        write_bit(port, (adr & 0x04) >> 2);
        write_bit(port, (adr & 0x02) >> 1);
        write_bit(port, (adr & 0x01) >> 0);
        
        j = read_bit(port);
        if (j == 1)
            j = read_bit(port);
        for (i=0; i<16; i++) {
            j = (j << 1) + read_bit(port);
        }
        write_bit(port, 1);
        return j;
    }
    int writea(int port, int adr, int val)
    {
        int i;
        
        outb(0x08, port);
        usleep(1);
        outb(0x0C, port);
        usleep(1);
        outb(0x08, port);
        usleep(1);
        outb(0x0C, port);
        outb(0x00, port);
        
        for (i=0; i<0x20; i++)
            write_bit(port, 1);
        
        write_bit(port, 0);
        write_bit(port, 1);
        write_bit(port, 0);
        write_bit(port, 1);
        
        write_bit(port, 0);
        write_bit(port, 0);
        write_bit(port, 0);
        write_bit(port, 0);
        write_bit(port, 0);
        
        write_bit(port, (adr & 0x10) >> 4);
        write_bit(port, (adr & 0x08) >> 3);
        write_bit(port, (adr & 0x04) >> 2);
        write_bit(port, (adr & 0x02) >> 1);
        write_bit(port, (adr & 0x01) >> 0);
        
        write_bit(port, 1);
        write_bit(port, 0);
        
        write_bit(port, (val & 0x8000) >> 15);
        write_bit(port, (val & 0x4000) >> 14);
        write_bit(port, (val & 0x2000) >> 13);
        write_bit(port, (val & 0x1000) >> 12);
        write_bit(port, (val & 0x0800) >> 11);
        write_bit(port, (val & 0x0400) >> 10);
        write_bit(port, (val & 0x0200) >> 9);
        write_bit(port, (val & 0x0100) >> 8);
        write_bit(port, (val & 0x0080) >> 7);
        write_bit(port, (val & 0x0040) >> 6);
        write_bit(port, (val & 0x0020) >> 5);
        write_bit(port, (val & 0x0010) >> 4);
        write_bit(port, (val & 0x0008) >> 3);
        write_bit(port, (val & 0x0004) >> 2);
        write_bit(port, (val & 0x0002) >> 1);
        write_bit(port, (val & 0x0001) >> 0);
        
        write_bit(port, 1);
        return 0;
    }
    int 
    main(int argc, char **argv)
    {
        int skfd, i, sub;
        struct ifreq ifr;
        
        skfd = sockets_open();
        if (skfd == -1) {
            perror("socket");
            exit(1);
        }
        strcpy(ifr.ifr_name, argv[1]);
    /*    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
            perror("ioctl");
            exit(1);
        }*/
        i = atoi(argv[2]);
        switch(i) {
        case 0:
            sub = 0x0000;
            break;
        case 1:
            sub = 0x0100;
            break;
        case 2:
            sub = 0x2000;
            break;
        default:
            sub = 0x2100;
            break;
        }
        i386_set_ioperm(BASE_ADDR+0x1c, 1, 1);
        reset(BASE_ADDR+0x1c);
        writea(BASE_ADDR+0x1c, 0, 0x8000);
        writea(BASE_ADDR+0x1c, 0, sub);
        close(skfd);
        exit(0);
        return 0;
    }

    You can find the source here: http://webperso.easynet.fr/fonvi/fa_select.c

    Don’t forget to change #define BASE_ADDR 0x240 with the card address.

    To compile it: gcc -Wall fa_select.c -o fa_select

    To use it:

        fa_select device rate
        
        where device is: ed0, ed1...
              rate is:  0       for 10BaseT
                        1       for 10Base2 (full duplex)
                        2       for 100BaseT
                        3       for 100Mbit (full duplex)
            

    I tried this with my adsl modem (Alcatel 1000 Adsl) with fa_select ed1 0 and
    it runs fine without timeout. It runs fine also on my on Lan.

Marc Fonvieille
fonvi@easynet.fr

Leave a Comment

Scroll to Top