The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/ether2000.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "io.h"
    7 #include "../port/error.h"
    8 #include "../port/netif.h"
    9 
   10 #include "etherif.h"
   11 #include "ether8390.h"
   12 
   13 /*
   14  * Driver written for the 'Notebook Computer Ethernet LAN Adapter',
   15  * a plug-in to the bus-slot on the rear of the Gateway NOMAD 425DXL
   16  * laptop. The manual says NE2000 compatible.
   17  * The interface appears to be pretty well described in the National
   18  * Semiconductor Local Area Network Databook (1992) as one of the
   19  * AT evaluation cards.
   20  *
   21  * The NE2000 is really just a DP8390[12] plus a data port
   22  * and a reset port.
   23  */
   24 enum {
   25         Data            = 0x10,         /* offset from I/O base of data port */
   26         Reset           = 0x1F,         /* offset from I/O base of reset port */
   27 };
   28 
   29 typedef struct Ctlr Ctlr;
   30 typedef struct Ctlr {
   31         Pcidev* pcidev;
   32         Ctlr*   next;
   33         int     active;
   34 } Ctlr;
   35 
   36 static Ctlr* ctlrhead;
   37 static Ctlr* ctlrtail;
   38 
   39 static struct {
   40         char*   name;
   41         int     id;
   42 } ne2000pci[] = {
   43         { "Realtek 8029",       (0x8029<<16)|0x10EC, },
   44         { "Winbond 89C940",     (0x0940<<16)|0x1050, },
   45         { nil },
   46 };
   47 
   48 static Ctlr*
   49 ne2000match(Ether* edev, int id)
   50 {
   51         int port;
   52         Pcidev *p;
   53         Ctlr *ctlr;
   54 
   55         /*
   56          * Any adapter matches if no edev->port is supplied,
   57          * otherwise the ports must match.
   58          */
   59         for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
   60                 if(ctlr->active)
   61                         continue;
   62                 p = ctlr->pcidev;
   63                 if(((p->did<<16)|p->vid) != id)
   64                         continue;
   65                 port = p->mem[0].bar & ~0x01;
   66                 if(edev->port != 0 && edev->port != port)
   67                         continue;
   68 
   69                 /*
   70                  * It suffices to fill these in,
   71                  * the rest is gleaned from the card.
   72                  */
   73                 edev->port = port;
   74                 edev->irq = p->intl;
   75 
   76                 ctlr->active = 1;
   77 
   78                 return ctlr;
   79         }
   80 
   81         return nil;
   82 }
   83 
   84 static void
   85 ne2000pnp(Ether* edev)
   86 {
   87         int i, id;
   88         Pcidev *p;
   89         Ctlr *ctlr;
   90 
   91         /*
   92          * Make a list of all ethernet controllers
   93          * if not already done.
   94          */
   95         if(ctlrhead == nil){
   96                 p = nil;
   97                 while(p = pcimatch(p, 0, 0)){
   98                         if(p->ccrb != 0x02 || p->ccru != 0)
   99                                 continue;
  100                         ctlr = malloc(sizeof(Ctlr));
  101                         ctlr->pcidev = p;
  102 
  103                         if(ctlrhead != nil)
  104                                 ctlrtail->next = ctlr;
  105                         else
  106                                 ctlrhead = ctlr;
  107                         ctlrtail = ctlr;
  108                 }
  109         }
  110 
  111         /*
  112          * Is it a card with an unrecognised vid+did?
  113          * Normally a search is made through all the found controllers
  114          * for one which matches any of the known vid+did pairs.
  115          * If a vid+did pair is specified a search is made for that
  116          * specific controller only.
  117          */
  118         id = 0;
  119         for(i = 0; i < edev->nopt; i++){
  120                 if(cistrncmp(edev->opt[i], "id=", 3) == 0)
  121                         id = strtol(&edev->opt[i][3], nil, 0);
  122         }
  123 
  124         if(id != 0)
  125                 ne2000match(edev, id);
  126         else for(i = 0; ne2000pci[i].name; i++){
  127                 if(ne2000match(edev, ne2000pci[i].id) != nil)
  128                         break;
  129         }
  130 }
  131 
  132 static int
  133 ne2000reset(Ether* edev)
  134 {
  135         ushort buf[16];
  136         ulong port;
  137         Dp8390 *dp8390;
  138         int i;
  139         uchar ea[Eaddrlen];
  140 
  141         if(edev->port == 0)
  142                 ne2000pnp(edev);
  143 
  144         /*
  145          * Set up the software configuration.
  146          * Use defaults for irq, mem and size
  147          * if not specified.
  148          * Must have a port, no more default.
  149          */
  150         if(edev->port == 0)
  151                 return -1;
  152         if(edev->irq == 0)
  153                 edev->irq = 2;
  154         if(edev->mem == 0)
  155                 edev->mem = 0x4000;
  156         if(edev->size == 0)
  157                 edev->size = 16*1024;
  158         port = edev->port;
  159 
  160         if(ioalloc(edev->port, 0x20, 0, "ne2000") < 0)
  161                 return -1;
  162 
  163         edev->ctlr = malloc(sizeof(Dp8390));
  164         dp8390 = edev->ctlr;
  165         dp8390->width = 2;
  166         dp8390->ram = 0;
  167 
  168         dp8390->port = port;
  169         dp8390->data = port+Data;
  170 
  171         dp8390->tstart = HOWMANY(edev->mem, Dp8390BufSz);
  172         dp8390->pstart = dp8390->tstart + HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
  173         dp8390->pstop = dp8390->tstart + HOWMANY(edev->size, Dp8390BufSz);
  174 
  175         dp8390->dummyrr = 1;
  176         for(i = 0; i < edev->nopt; i++){
  177                 if(strcmp(edev->opt[i], "nodummyrr"))
  178                         continue;
  179                 dp8390->dummyrr = 0;
  180                 break;
  181         }
  182 
  183         /*
  184          * Reset the board. This is done by doing a read
  185          * followed by a write to the Reset address.
  186          */
  187         buf[0] = inb(port+Reset);
  188         delay(2);
  189         outb(port+Reset, buf[0]);
  190         delay(2);
  191         
  192         /*
  193          * Init the (possible) chip, then use the (possible)
  194          * chip to read the (possible) PROM for ethernet address
  195          * and a marker byte.
  196          * Could just look at the DP8390 command register after
  197          * initialisation has been tried, but that wouldn't be
  198          * enough, there are other ethernet boards which could
  199          * match.
  200          * Parallels has buf[0x0E] == 0x00 whereas real hardware
  201          * usually has 0x57.
  202          */
  203         dp8390reset(edev);
  204         memset(buf, 0, sizeof(buf));
  205         dp8390read(dp8390, buf, 0, sizeof(buf));
  206         i = buf[0x0E] & 0xFF;
  207         if((i != 0x00 && i != 0x57) || (buf[0x0F] & 0xFF) != 0x57){
  208                 iofree(edev->port);
  209                 free(edev->ctlr);
  210                 return -1;
  211         }
  212 
  213         /*
  214          * Stupid machine. Shorts were asked for,
  215          * shorts were delivered, although the PROM is a byte array.
  216          * Set the ethernet address.
  217          */
  218         memset(ea, 0, Eaddrlen);
  219         if(memcmp(ea, edev->ea, Eaddrlen) == 0){
  220                 for(i = 0; i < sizeof(edev->ea); i++)
  221                         edev->ea[i] = buf[i];
  222         }
  223         dp8390setea(edev);
  224 
  225         return 0;
  226 }
  227 
  228 void
  229 ether2000link(void)
  230 {
  231         addethercard("NE2000", ne2000reset);
  232 }

Cache object: e2fcde714b08fa32379c6ad7bc0fab53


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.