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/ether8003.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  * Western Digital/Standard Microsystems Corporation cards (WD80[01]3).
   15  * Also handles 8216 cards (Elite Ultra).
   16  * Configuration code based on that provided by SMC a long time ago.
   17  */
   18 enum {                                  /* 83C584 Bus Interface Controller */
   19         Msr             = 0x00,         /* Memory Select Register */
   20         Icr             = 0x01,         /* Interface Configuration Register */
   21         Iar             = 0x02,         /* I/O Address Register */
   22         Bio             = 0x03,         /* BIOS ROM Address Register */
   23         Ear             = 0x03,         /* EEROM Address Register (shared with Bio) */
   24         Irr             = 0x04,         /* Interrupt Request Register */
   25         Hcr             = 0x04,         /* 8216 hardware control */
   26         Laar            = 0x05,         /* LA Address Register */
   27         Ijr             = 0x06,         /* Initialisation Jumpers */
   28         Gp2             = 0x07,         /* General Purpose Data Register */
   29         Lar             = 0x08,         /* LAN Address Registers */
   30         Id              = 0x0E,         /* Card ID byte */
   31         Cksum           = 0x0F,         /* Checksum */
   32 };
   33 
   34 enum {                                  /* Msr */
   35         Rst             = 0x80,         /* software reset */
   36         Menb            = 0x40,         /* memory enable */
   37 };
   38 
   39 enum {                                  /* Icr */
   40         Bit16           = 0x01,         /* 16-bit bus */
   41         Other           = 0x02,         /* other register access */
   42         Ir2             = 0x04,         /* IR2 */
   43         Msz             = 0x08,         /* SRAM size */
   44         Rla             = 0x10,         /* recall LAN address */
   45         Rx7             = 0x20,         /* recall all but I/O and LAN address */
   46         Rio             = 0x40,         /* recall I/O address from EEROM */
   47         Sto             = 0x80,         /* non-volatile EEROM store */
   48 };
   49 
   50 enum {                                  /* Laar */
   51         ZeroWS16        = 0x20,         /* zero wait states for 16-bit ops */
   52         L16en           = 0x40,         /* enable 16-bit LAN operation */
   53         M16en           = 0x80,         /* enable 16-bit memory access */
   54 };
   55 
   56 enum {                                  /* Ijr */
   57         Ienable         = 0x01,         /* 8216 interrupt enable */
   58 };
   59 
   60 /*
   61  * Mapping from configuration bits to interrupt level.
   62  */
   63 static int irq8003[8] = {
   64         9, 3, 5, 7, 10, 11, 15, 4,
   65 };
   66 
   67 static int irq8216[8] = {
   68         0, 9, 3, 5, 7, 10, 11, 15,
   69 };
   70 
   71 static void
   72 reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8])
   73 {
   74         Dp8390 *ctlr;
   75         ulong port;
   76 
   77         ctlr = ether->ctlr;
   78         port = ether->port;
   79 
   80         /*
   81          * Check for old, dumb 8003E, which doesn't have an interface
   82          * chip. Only Msr exists out of the 1st eight registers, reads
   83          * of the others just alias the 2nd eight registers, the LAN
   84          * address ROM. Can check Icr, Irr and Laar against the ethernet
   85          * address read above and if they match it's an 8003E (or an
   86          * 8003EBT, 8003S, 8003SH or 8003WT, doesn't matter), in which
   87          * case the default irq gets used.
   88          */
   89         if(memcmp(&ea[1], &ic[1], 5) == 0){
   90                 memset(ic, 0, sizeof(ic));
   91                 ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
   92         }
   93         else{
   94                 /*
   95                  * As a final sanity check for the 8013EBT, which doesn't have
   96                  * the 83C584 interface chip, but has 2 real registers, write Gp2
   97                  * and if it reads back the same, it's not an 8013EBT.
   98                  */
   99                 outb(port+Gp2, 0xAA);
  100                 inb(port+Msr);                          /* wiggle bus */
  101                 if(inb(port+Gp2) != 0xAA){
  102                         memset(ic, 0, sizeof(ic));
  103                         ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
  104                 }
  105                 else
  106                         ether->irq = irq8003[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)];
  107 
  108                 /*
  109                  * Check if 16-bit card.
  110                  * If Bit16 is read/write, then it's an 8-bit card.
  111                  * If Bit16 is set, it's in a 16-bit slot.
  112                  */
  113                 outb(port+Icr, ic[Icr]^Bit16);
  114                 inb(port+Msr);                          /* wiggle bus */
  115                 if((inb(port+Icr) & Bit16) == (ic[Icr] & Bit16)){
  116                         ctlr->width = 2;
  117                         ic[Icr] &= ~Bit16;
  118                 }
  119                 outb(port+Icr, ic[Icr]);
  120 
  121                 if(ctlr->width == 2 && (inb(port+Icr) & Bit16) == 0)
  122                         ctlr->width = 1;
  123         }
  124 
  125         ether->mem = (ulong)KADDR((ic[Msr] & 0x3F)<<13);
  126         if(ctlr->width == 2)
  127                 ether->mem |= (ic[Laar] & 0x1F)<<19;
  128         else
  129                 ether->mem |= 0x80000;
  130 
  131         if(ic[Icr] & (1<<3))
  132                 ether->size = 32*1024;
  133         if(ctlr->width == 2)
  134                 ether->size <<= 1;
  135 
  136         /*
  137          * Enable interface RAM, set interface width.
  138          */
  139         outb(port+Msr, ic[Msr]|Menb);
  140         if(ctlr->width == 2)
  141                 outb(port+Laar, ic[Laar]|L16en|M16en|ZeroWS16);
  142 }
  143 
  144 static void
  145 reset8216(Ether* ether, uchar[8])
  146 {
  147         uchar hcr, irq, x;
  148         ulong addr, port;
  149         Dp8390 *ctlr;
  150 
  151         ctlr = ether->ctlr;
  152         port = ether->port;
  153 
  154         ctlr->width = 2;
  155 
  156         /*
  157          * Switch to the alternate register set and retrieve the memory
  158          * and irq information.
  159          */
  160         hcr = inb(port+Hcr);
  161         outb(port+Hcr, 0x80|hcr);
  162         addr = inb(port+0x0B) & 0xFF;
  163         irq = inb(port+0x0D);
  164         outb(port+Hcr, hcr);
  165 
  166         ether->mem = (ulong)KADDR(0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13));
  167         ether->size = 8192*(1<<((addr>>4) & 0x03));
  168         ether->irq = irq8216[((irq>>4) & 0x04)|((irq>>2) & 0x03)];
  169 
  170         /*
  171          * Enable interface RAM, set interface width, and enable interrupts.
  172          */
  173         x = inb(port+Msr) & ~Rst;
  174         outb(port+Msr, Menb|x);
  175         x = inb(port+Laar);
  176         outb(port+Laar, M16en|x);
  177         outb(port+Ijr, Ienable);
  178 }
  179 
  180 /*
  181  * Get configuration parameters, enable memory.
  182  * There are opportunities here for buckets of code, try to resist.
  183  */
  184 static int
  185 reset(Ether* ether)
  186 {
  187         int i;
  188         uchar ea[Eaddrlen], ic[8], id, nullea[Eaddrlen], sum;
  189         ulong port;
  190         Dp8390 *ctlr;
  191 
  192         /*
  193          * Set up the software configuration.
  194          * Use defaults for port, irq, mem and size if not specified.
  195          * Defaults are set for the dumb 8003E which can't be
  196          * autoconfigured.
  197          */
  198         if(ether->port == 0)
  199                 ether->port = 0x280;
  200         if(ether->irq == 0)
  201                 ether->irq = 3;
  202         if(ether->mem == 0)
  203                 ether->mem = 0xD0000;
  204         if(ether->size == 0)
  205                 ether->size = 8*1024;
  206         if(ioalloc(ether->port, 0x20, 0, "wd8003") < 0)
  207                 return -1;
  208 
  209         /*
  210          * Look for the interface. Read the LAN address ROM
  211          * and validate the checksum - the sum of all 8 bytes
  212          * should be 0xFF.
  213          * At the same time, get the (possible) interface chip
  214          * registers, they'll be used later to check for aliasing.
  215          */
  216         port = ether->port;
  217         sum = 0;
  218         for(i = 0; i < sizeof(ea); i++){
  219                 ea[i] = inb(port+Lar+i);
  220                 sum += ea[i];
  221                 ic[i] = inb(port+i);
  222         }
  223         id = inb(port+Id);
  224         sum += id;
  225         sum += inb(port+Cksum);
  226         if(sum != 0xFF){
  227                 iofree(ether->port);
  228                 return -1;
  229         }
  230 
  231         ether->ctlr = malloc(sizeof(Dp8390));
  232         ctlr = ether->ctlr;
  233         ctlr->ram = 1;
  234 
  235         if((id & 0xFE) == 0x2A)
  236                 reset8216(ether, ic);
  237         else
  238                 reset8003(ether, ea, ic);
  239 
  240         /*
  241          * Set the DP8390 ring addresses.
  242          */
  243         ctlr->port = port+0x10;
  244         ctlr->tstart = 0;
  245         ctlr->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
  246         ctlr->pstop = HOWMANY(ether->size, Dp8390BufSz);
  247 
  248         /*
  249          * Finally, init the 8390, set the ethernet address
  250          * and claim the memory used.
  251          */
  252         dp8390reset(ether);
  253         memset(nullea, 0, Eaddrlen);
  254         if(memcmp(nullea, ether->ea, Eaddrlen) == 0){
  255                 for(i = 0; i < sizeof(ether->ea); i++)
  256                         ether->ea[i] = ea[i];
  257         }
  258         dp8390setea(ether);
  259 
  260         if(umbrwmalloc(PADDR(ether->mem), ether->size, 0) == 0)
  261                 print("ether8003: warning - 0x%luX unavailable\n",
  262                         PADDR(ether->mem));
  263 
  264         return 0;
  265 }
  266 
  267 void
  268 ether8003link(void)
  269 {
  270         addethercard("WD8003", reset);
  271 }

Cache object: 434a5b2d85ad58d15b8708742c194096


[ 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.