The FreeBSD Diary

The FreeBSD Diary (TM)

Providing practical examples since 1998

If you buy from Amazon USA, please support us by using this link.
[ HOME | TOPICS | INDEX | WEB RESOURCES | BOOKS | CONTRIBUTE | SEARCH | FEEDBACK | FAQ | FORUMS ]
Last Netgear's FA410TX pcmcia ethernet card and FreeBSD 4.x --- by Marc Fonvieille 12 August 2000
Need more help on this topic? Click here
This article has no comments
Show me similar articles
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


Need more help on this topic? Click here
This article has no comments
Show me similar articles