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/ethersmc.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 /*
    2  * SMC EtherEZ (SMC91cXX chip) PCMCIA card support.
    3  */
    4 
    5 #include "u.h"
    6 #include "../port/lib.h"
    7 #include "mem.h"
    8 #include "dat.h"
    9 #include "fns.h"
   10 #include "io.h"
   11 #include "../port/error.h"
   12 #include "../port/netif.h"
   13 #include "etherif.h"
   14 
   15 enum {
   16         IoSize          = 0x10,         /* port pool size */
   17         TxTimeout       = 150,
   18 };
   19 
   20 enum {  /* PCMCIA related */
   21         TupleFunce      = 0x22,
   22         TfNodeId        = 0x04,
   23 };
   24 
   25 enum {  /* bank 0 registers */
   26         Tcr             = 0x0000,       /* transmit control */
   27         Eph             = 0x0002,       /* ethernet protocol handler */
   28         Rcr             = 0x0004,       /* receiver control */
   29         Counter         = 0x0006,       /* statistics counter */
   30         MemInfo         = 0x0008,
   31         MemCfg          = 0x000A,
   32 };
   33 
   34 enum {  /* bank 1 registers */
   35         Config          = 0x0000,
   36         BaseAddr        = 0x0002,
   37         Addr0           = 0x0004,       /* ethernet address */
   38         Addr1           = 0x0006,
   39         Addr2           = 0x0008,
   40         General         = 0x000A,
   41         Control         = 0x000C,
   42 };
   43 
   44 enum {  /* bank 2 registers */
   45         MmuCmd          = 0x0000,
   46         PktNo           = 0x0002,
   47         AllocRes        = 0x0003,
   48         FifoPorts       = 0x0004,
   49         Pointer         = 0x0006,
   50         Data1           = 0x0008,
   51         Interrupt       = 0x000C,
   52         IntrMask        = 0x000D,
   53 };
   54 
   55 enum {  /* bank 3 registers */
   56         Mcast0          = 0x0000,
   57         Mcast2          = 0x0002,
   58         Mcast4          = 0x0004,
   59         Mcast6          = 0x0006,
   60         Revision        = 0x000A,
   61 };
   62 
   63 enum {
   64         BankSelect      = 0x000E        /* bank select register */
   65 };
   66 
   67 enum {
   68         BsrMask         = 0xFF00,       /* mask for chip identification */
   69         BsrId           = 0x3300,
   70 };
   71 
   72 
   73 enum {  /* Tcr values */
   74         TcrClear        = 0x0000,
   75         TcrEnable       = 0x0001,       /* enable transmit */
   76         TcrLoop         = 0x0002,       /* enable internal analogue loopback */
   77         TcrForceCol     = 0x0004,       /* force collision on next tx */
   78         TcrPadEn        = 0x0080,       /* pad short packets to 64 bytes */
   79         TcrNoCrc        = 0x0100,       /* do not append CRC */
   80         TcrMonCns       = 0x0400,       /* monitor carrier status */
   81         TcrFduplx       = 0x0800,
   82         TcrStpSqet      = 0x1000,
   83         TcrEphLoop      = 0x2000,
   84         TcrNormal       = TcrEnable,
   85 };
   86 
   87 enum {  /* Eph values */
   88         EphTxOk         = 0x0001,
   89         Eph1Col         = 0x0002,       /* single collision */
   90         EphMCol         = 0x0004,       /* multiple collisions */  
   91         EphTxMcast      = 0x0008,       /* multicast transmit */
   92         Eph16Col        = 0x0010,       /* 16 collisions, tx disabled */
   93         EphSqet         = 0x0020,       /* SQE test failed, tx disabled */
   94         EphTxBcast      = 0x0040,       /* broadcast tx */
   95         EphDefr         = 0x0080,       /* deffered tx */
   96         EphLatCol       = 0x0200,       /* late collision, tx disabled */
   97         EphLostCarr     = 0x0400,       /* lost carrier, tx disabled */
   98         EphExcDefr      = 0x0800,       /* excessive defferals */
   99         EphCntRol       = 0x1000,       /* ECR counter(s) rolled over */
  100         EphRxOvrn       = 0x2000,       /* receiver overrun, packets dropped */
  101         EphLinkOk       = 0x4000,
  102         EphTxUnrn       = 0x8000,       /* tx underrun */
  103 };
  104 
  105 enum {  /* Rcr values */
  106         RcrClear        = 0x0000,
  107         RcrPromisc      = 0x0002,
  108         RcrAllMcast     = 0x0004,
  109         RcrEnable       = 0x0100,
  110         RcrStripCrc     = 0x0200,
  111         RcrSoftReset    = 0x8000,
  112         RcrNormal       = RcrStripCrc | RcrEnable,
  113 };
  114 
  115 enum { /* Counter value masks */
  116         CntColMask      = 0x000F,       /* collisions */
  117         CntMColMask     = 0x00F0,       /* multiple collisions */
  118         CntDtxMask      = 0x0F00,       /* deferred transmits */
  119         CntExDtxMask    = 0xF000,       /* excessively deferred transmits */
  120 
  121         CntColShr       = 1,
  122         CntMColShr      = 4,
  123         CntDtxShr       = 8,
  124 };
  125 
  126 enum { /* MemInfo value masks */
  127         MirTotalMask    = 0x00FF,
  128         MirFreeMask     = 0xFF00,
  129 };
  130 
  131 enum {  /* Config values */
  132         CfgIrqSel0      = 0x0002,
  133         CfgIrqSel1      = 0x0004,
  134         CfgDisLink      = 0x0040,       /* disable 10BaseT link test */
  135         Cfg16Bit        = 0x0080,
  136         CfgAuiSelect    = 0x0100,
  137         CfgSetSqlch     = 0x0200,
  138         CfgFullStep     = 0x0400,
  139         CfgNoWait       = 0x1000,
  140         CfgMiiSelect    = 0x8000,
  141 };
  142 
  143 enum {  /* Control values */
  144         CtlStore        = 0x0001,       /* store to EEPROM */
  145         CtlReload       = 0x0002,       /* reload EEPROM into registers */
  146         CtlEeSelect     = 0x0004,       /* select registers for reload/store */
  147         CtlTeEnable     = 0x0020,       /* tx error detection via eph irq */
  148         CtlCrEnable     = 0x0040,       /* counter rollover via eph irq */
  149         CtlLeEnable     = 0x0080,       /* link error detection via eph irq*/
  150         CtlAutoRls      = 0x0800,       /* auto release mode */
  151         CtlPowerDn      = 0x2000,
  152 };
  153 
  154 enum {  /* MmuCmd values */
  155         McBusy          = 0x0001,
  156         McAlloc         = 0x0020,       /* | with number of 256 byte packets - 1 */
  157         McReset         = 0x0040,
  158         McRelease       = 0x0080,       /* dequeue (but not free) current rx packet */
  159         McFreePkt       = 0x00A0,       /* dequeue and free current rx packet */
  160         McEnqueue       = 0x00C0,       /* enqueue the packet for tx */
  161         McTxReset       = 0x00E0,       /* reset transmit queues */
  162 };
  163 
  164 enum { /* AllocRes values */
  165         ArFailed        = 0x80,
  166 };
  167           
  168 enum {  /* FifoPorts values */
  169         FpTxEmpty       = 0x0080,
  170         FpRxEmpty       = 0x8000,
  171         FpTxMask        = 0x007F,
  172         FpRxMask        = 0x7F00,
  173 };
  174 
  175 enum {  /* Pointer values */
  176         PtrRead         = 0x2000,
  177         PtrAutoInc      = 0x4000,
  178         PtrRcv          = 0x8000,
  179 };
  180 
  181 enum {  /* Interrupt values */
  182         IntRcv          = 0x0001,
  183         IntTxError      = 0x0002,
  184         IntTxEmpty      = 0x0004,
  185         IntAlloc        = 0x0008,
  186         IntRxOvrn       = 0x0010,
  187         IntEph          = 0x0020,
  188 };
  189 
  190 enum { /* transmit status bits */
  191         TsSuccess       = 0x0001,
  192         Ts16Col         = 0x00A0,
  193         TsLatCol        = 0x0200,
  194         TsLostCar       = 0x0400,
  195 };
  196 
  197 enum { /* receive status bits */
  198         RsMcast         = 0x0001,
  199         RsTooShort      = 0x0400,
  200         RsTooLong       = 0x0800,
  201         RsOddFrame      = 0x1000,
  202         RsBadCrc        = 0x2000,
  203         RsAlgnErr       = 0x8000,
  204         RsError         = RsAlgnErr | RsBadCrc | RsTooLong | RsTooShort,
  205 };
  206 
  207 enum {
  208         RxLenMask       = 0x07FF,       /* significant rx len bits */
  209         HdrSize         = 6,            /* packet header length */
  210         PageSize        = 256,          /* page length */
  211 };
  212 
  213 typedef struct Smc91xx Smc91xx;
  214 struct Smc91xx {
  215         Lock;
  216         ushort rev;
  217         int attached;
  218         Block *txbp;
  219         ulong txtime;
  220 
  221         ulong rovrn;
  222         ulong lcar;
  223         ulong col;
  224         ulong scol;
  225         ulong mcol;
  226         ulong lcol;
  227         ulong dfr;
  228 };
  229 
  230 #define SELECT_BANK(x) outs(port + BankSelect, x)
  231 
  232 static int
  233 readnodeid(int slot, Ether* ether)
  234 {
  235         uchar data[Eaddrlen + 1];
  236         int len;
  237 
  238         len = sizeof(data);
  239         if (pcmcistuple(slot, TupleFunce, TfNodeId, data, len) != len)
  240                 return -1;
  241 
  242         if (data[0] != Eaddrlen)
  243                 return -1;
  244 
  245         memmove(ether->ea, &data[1], Eaddrlen);
  246         return 0;
  247 }
  248 
  249 static void
  250 chipreset(Ether* ether)
  251 {
  252         int port;
  253         int i;
  254 
  255         port = ether->port;
  256 
  257         /* reset the chip */
  258         SELECT_BANK(0);
  259         outs(port + Rcr, RcrSoftReset);
  260         delay(1);
  261         outs(port + Rcr, RcrClear);
  262         outs(port + Tcr, TcrClear);
  263         SELECT_BANK(1);
  264         outs(port + Control, CtlAutoRls | CtlTeEnable |
  265                 CtlCrEnable);
  266 
  267         for(i = 0; i < 6; i++) {
  268                 outb(port + Addr0 +  i, ether->ea[i]);
  269         }
  270 
  271         SELECT_BANK(2);
  272         outs(port + MmuCmd, McReset);
  273 }
  274 
  275 static void
  276 chipenable(Ether* ether)
  277 {
  278         int port;
  279 
  280         port = ether->port;
  281         SELECT_BANK(0);
  282         outs(port + Tcr, TcrNormal);
  283         outs(port + Rcr, RcrNormal);
  284         SELECT_BANK(2);
  285         outb(port + IntrMask, IntEph | IntRxOvrn | IntRcv);
  286 }
  287 
  288 static void
  289 attach(Ether *ether)
  290 {
  291         Smc91xx* ctlr;
  292 
  293         ctlr = ether->ctlr;
  294         ilock(ctlr);
  295         
  296         if (ctlr->attached) {
  297                 iunlock(ctlr);
  298                 return;
  299         }
  300 
  301         chipenable(ether);
  302         ctlr->attached = 1;
  303         iunlock(ctlr);
  304 }
  305 
  306 static void
  307 txstart(Ether* ether)
  308 {
  309         int port;
  310         Smc91xx* ctlr;
  311         Block* bp;
  312         int len, npages;
  313         int pno;
  314 
  315         /* assumes ctlr is locked and bank 2 is selected */
  316         /* leaves bank 2 selected on return */
  317         port = ether->port;
  318         ctlr = ether->ctlr;
  319 
  320         if (ctlr->txbp) {
  321                 bp = ctlr->txbp;
  322                 ctlr->txbp = 0;
  323         } else {
  324                 bp = qget(ether->oq);
  325                 if (bp == 0)
  326                         return;
  327 
  328                 len = BLEN(bp);
  329                 npages = (len + HdrSize) / PageSize;
  330                 outs(port + MmuCmd, McAlloc | npages);
  331         }
  332 
  333         pno = inb(port + AllocRes);
  334         if (pno & ArFailed) {
  335                 outb(port + IntrMask, inb(port + IntrMask) | IntAlloc);
  336                 ctlr->txbp = bp;
  337                 ctlr->txtime = MACHP(0)->ticks;
  338                 return;
  339         }
  340 
  341         outb(port + PktNo, pno);
  342         outs(port + Pointer, PtrAutoInc);
  343 
  344         len = BLEN(bp);
  345         outs(port + Data1, 0);
  346         outb(port + Data1, (len + HdrSize) & 0xFF);
  347         outb(port + Data1, (len + HdrSize) >> 8);
  348         outss(port + Data1, bp->rp, len / 2);
  349         if ((len & 1) == 0) {
  350                 outs(port + Data1, 0);
  351         } else {
  352                 outb(port + Data1, bp->rp[len - 1]);
  353                 outb(port + Data1, 0x20);       /* no info what 0x20 means */
  354         }
  355 
  356         outb(port + IntrMask, inb(port + IntrMask) |
  357                         IntTxError | IntTxEmpty);
  358 
  359         outs(port + MmuCmd, McEnqueue);
  360         freeb(bp);
  361 }
  362 
  363 static void
  364 receive(Ether* ether)
  365 {
  366         int port;
  367         Block* bp;
  368         int pktno, status, len;
  369 
  370         /* assumes ctlr is locked and bank 2 is selected */
  371         /* leaves bank 2 selected on return */
  372         port = ether->port;
  373 
  374         pktno = ins(port + FifoPorts);
  375         if (pktno & FpRxEmpty) {
  376                 return;
  377         }
  378 
  379         outs(port + Pointer, PtrRead | PtrRcv | PtrAutoInc);
  380         status = ins(port + Data1);
  381         len = ins(port + Data1) & RxLenMask - HdrSize;
  382         
  383         if (status & RsOddFrame)
  384                 len++;
  385         
  386         if ((status & RsError) || (bp = iallocb(len)) == 0) {
  387 
  388                 if (status & RsAlgnErr)
  389                         ether->frames++;
  390                 if (status & (RsTooShort | RsTooLong))
  391                         ether->buffs++;
  392                 if (status & RsBadCrc)
  393                         ether->crcs++;
  394 
  395                 outs(port + MmuCmd, McRelease);
  396                 return;
  397         }
  398 
  399         /* packet length is padded to word */
  400         inss(port + Data1, bp->rp, len / 2);
  401         bp->wp = bp->rp + (len & ~1);
  402         
  403         if (len & 1) {
  404                 *bp->wp = inb(port + Data1);
  405                 bp->wp++;
  406         }
  407           
  408         etheriq(ether, bp, 1);
  409         ether->inpackets++;
  410         outs(port + MmuCmd, McRelease);
  411 }
  412 
  413 static void
  414 txerror(Ether* ether)
  415 {
  416         int port;
  417         Smc91xx* ctlr;
  418         int save_pkt;
  419         int pktno, status;
  420 
  421         /* assumes ctlr is locked and bank 2 is selected */
  422         /* leaves bank 2 selected on return */
  423         port = ether->port;
  424         ctlr = ether->ctlr;
  425 
  426         save_pkt = inb(port + PktNo);
  427 
  428         pktno = ins(port + FifoPorts) & FpTxMask;
  429         outb(port + PktNo, pktno);
  430         outs(port + Pointer, PtrAutoInc | PtrRead);
  431         status = ins(port + Data1);
  432         
  433         if (status & TsLostCar)
  434                 ctlr->lcar++;
  435 
  436         if (status & TsLatCol)
  437                 ctlr->lcol++;
  438 
  439         if (status & Ts16Col)
  440                 ctlr->scol++;
  441 
  442         ether->oerrs++;
  443         
  444         SELECT_BANK(0);
  445         outs(port + Tcr, ins(port + Tcr) | TcrEnable);
  446         
  447         SELECT_BANK(2);
  448         outs(port + MmuCmd, McFreePkt);
  449 
  450         outb(port + PktNo, save_pkt);
  451 }
  452 
  453 static void
  454 eph_irq(Ether* ether)
  455 {
  456         int port;
  457         Smc91xx* ctlr;
  458         ushort status;
  459         int n;
  460 
  461         /* assumes ctlr is locked and bank 2 is selected */
  462         /* leaves bank 2 selected on return */
  463         port = ether->port;
  464         ctlr = ether->ctlr;
  465 
  466         SELECT_BANK(0);
  467         status = ins(port + Eph);
  468 
  469         if (status & EphCntRol) {
  470                 /* read the counter register even if we don't need it */
  471                 /* otherwise we will keep getting this interrupt */
  472                 n = ins(port + Counter);
  473                 ctlr->col += (n & CntColMask) >> CntColShr;
  474                 ctlr->mcol += (n & CntMColMask) >> CntMColShr;
  475                 ctlr->dfr += (n & CntDtxMask) >> CntDtxShr;
  476         }
  477 
  478         /* if there was a transmit error, Tcr is disabled */
  479         outs(port + Tcr, ins(port + Tcr) | TcrEnable);
  480 
  481         /* clear a link error interrupt */
  482         SELECT_BANK(1);
  483         outs(port + Control, CtlAutoRls);
  484         outs(port + Control, CtlAutoRls | CtlTeEnable | CtlCrEnable);
  485 
  486         SELECT_BANK(2);
  487 }
  488 
  489 static void
  490 transmit(Ether* ether)
  491 {
  492         Smc91xx* ctlr;
  493         int port, n;
  494 
  495         ctlr = ether->ctlr;
  496         port = ether->port;
  497         ilock(ctlr);
  498 
  499         if (ctlr->txbp) {
  500                 n = TK2MS(MACHP(0)->ticks - ctlr->txtime);
  501                 if (n > TxTimeout) {
  502                         chipreset(ether);
  503                         chipenable(ether);
  504                         freeb(ctlr->txbp);
  505                         ctlr->txbp = 0;
  506                 }
  507                 iunlock(ctlr);
  508                 return;
  509         }
  510 
  511         SELECT_BANK(2);
  512         txstart(ether);
  513         iunlock(ctlr);
  514 }
  515 
  516 static void
  517 interrupt(Ureg*, void *arg)
  518 {
  519         int port;
  520         Smc91xx* ctlr;
  521         Ether* ether;
  522         int save_bank;
  523         int save_pointer;
  524         int mask, status;
  525 
  526         ether = arg;
  527         port = ether->port;
  528         ctlr = ether->ctlr;
  529         
  530         ilock(ctlr);
  531         save_bank = ins(port + BankSelect);
  532         SELECT_BANK(2);
  533         save_pointer = ins(port + Pointer);
  534         
  535         mask = inb(port + IntrMask);
  536         outb(port + IntrMask, 0);
  537 
  538         while ((status = inb(port + Interrupt) & mask) != 0) {
  539                 if (status & IntRcv) {
  540                         receive(ether);
  541                 }
  542 
  543                 if (status & IntTxError) {
  544                         txerror(ether);
  545                 }
  546 
  547                 if (status & IntTxEmpty) {
  548                         outb(port + Interrupt, IntTxEmpty);
  549                         outb(port + IntrMask, mask & ~IntTxEmpty);
  550                         txstart(ether);
  551                         mask = inb(port + IntrMask);
  552                 }
  553 
  554                 if (status & IntAlloc) {
  555                         outb(port + IntrMask, mask & ~IntAlloc);
  556                         txstart(ether);;
  557                         mask = inb(port + IntrMask);
  558                 }
  559 
  560                 if (status & IntRxOvrn) {
  561                         ctlr->rovrn++;
  562                         ether->misses++;
  563                         outb(port + Interrupt,IntRxOvrn);
  564                 }
  565 
  566                 if (status & IntEph)
  567                         eph_irq(ether);
  568         }
  569         
  570         outb(port + IntrMask, mask);
  571         outs(port + Pointer, save_pointer);
  572         outs(port + BankSelect, save_bank);
  573         iunlock(ctlr);
  574 }
  575 
  576 static void
  577 promiscuous(void* arg, int on)
  578 {
  579         int port;
  580         Smc91xx *ctlr;
  581         Ether* ether;
  582         ushort x;
  583 
  584         ether = arg;
  585         port = ether->port;
  586         ctlr = ether->ctlr;
  587 
  588         ilock(ctlr);
  589         SELECT_BANK(0);
  590         x = ins(port + Rcr);
  591         if (on)
  592                 x |= RcrPromisc;
  593         else
  594                 x &= ~RcrPromisc;
  595         
  596         outs(port + Rcr, x);
  597         iunlock(ctlr);
  598 }
  599 
  600 static void
  601 multicast(void* arg, uchar *addr, int on)
  602 {
  603         int port;
  604         Smc91xx*ctlr;
  605         Ether *ether;
  606         ushort x;
  607         
  608         USED(addr, on);
  609 
  610         ether = arg;
  611         port = ether->port;
  612         ctlr = ether->ctlr;
  613         ilock(ctlr);
  614         
  615         SELECT_BANK(0);
  616         x = ins(port + Rcr);
  617         
  618         if (ether->nmaddr)
  619                 x |= RcrAllMcast;
  620         else
  621                 x &= ~RcrAllMcast;
  622         
  623         outs(port + Rcr, x);
  624         iunlock(ctlr);
  625 }
  626 
  627 static long
  628 ifstat(Ether* ether, void* a, long n, ulong offset)
  629 {
  630         static char *chiprev[] = {
  631                 [3]     "92",
  632                 [5]     "95",
  633                 [7]     "100",
  634                 [8]     "100-FD",
  635                 [9]     "110",
  636         };
  637 
  638         Smc91xx* ctlr;
  639         char* p;
  640         int r, len;
  641         char* s;
  642         
  643         if (n == 0)
  644                 return 0;
  645 
  646         ctlr = ether->ctlr;
  647         p = malloc(READSTR);
  648 
  649         s = 0;
  650         if (ctlr->rev > 0) {
  651                 r = ctlr->rev >> 4;
  652                 if (r < nelem(chiprev))
  653                         s = chiprev[r];
  654 
  655                 if (r == 4) {
  656                         if ((ctlr->rev & 0x0F) >= 6)
  657                                 s = "96";
  658                         else
  659                                 s = "94";
  660                 }
  661         }
  662 
  663         len = snprint(p, READSTR, "rev: 91c%s\n", (s) ? s : "???");
  664         len += snprint(p + len, READSTR - len, "rxovrn: %uld\n", ctlr->rovrn);
  665         len += snprint(p + len, READSTR - len, "lcar: %uld\n", ctlr->lcar);
  666         len += snprint(p + len, READSTR - len, "col: %uld\n", ctlr->col);
  667         len += snprint(p + len, READSTR - len, "16col: %uld\n", ctlr->scol);
  668         len += snprint(p + len, READSTR - len, "mcol: %uld\n", ctlr->mcol);
  669         len += snprint(p + len, READSTR - len, "lcol: %uld\n", ctlr->lcol);
  670         len += snprint(p + len, READSTR - len, "dfr: %uld\n", ctlr->dfr);
  671         USED(len);
  672 
  673         n = readstr(offset, a, n, p);
  674         free(p);
  675         
  676         return n;
  677 }
  678 
  679 static int
  680 reset(Ether* ether)
  681 {
  682         int port;
  683         int i, x;
  684         char* type;
  685         Smc91xx* ctlr;
  686         int slot;
  687         uchar ea[Eaddrlen];
  688 
  689         if (ether->irq == 0)
  690                 ether->irq = 9;
  691 
  692         if (ether->port == 0)
  693                 ether->port = 0x100;
  694 
  695         type = "8020";
  696         for(i = 0; i < ether->nopt; i++) {
  697                 if (cistrncmp(ether->opt[i], "id=", 3))
  698                         continue;
  699                 type = &ether->opt[i][3];
  700                 break;
  701         }
  702 
  703         if ((slot = pcmspecial(type, ether)) < 0)
  704                 return -1;
  705 
  706         if (ioalloc(ether->port, IoSize, 0, "smc91cXX") < 0) {
  707                 pcmspecialclose(slot);
  708                 return -1;
  709         }
  710 
  711         ether->ctlr = malloc(sizeof(Smc91xx));
  712         ctlr = ether->ctlr;
  713         if (ctlr == 0) {
  714                 iofree(ether->port);
  715                 pcmspecialclose(slot);
  716                 return -1;
  717         }
  718 
  719         ilock(ctlr);
  720         ctlr->rev = 0;
  721         ctlr->txbp = nil;
  722         ctlr->attached = 0;
  723         ctlr->rovrn = 0;
  724         ctlr->lcar = 0;
  725         ctlr->col = 0;
  726         ctlr->scol = 0;
  727         ctlr->mcol = 0;
  728         ctlr->lcol = 0;
  729         ctlr->dfr = 0;
  730 
  731         port = ether->port;
  732 
  733         SELECT_BANK(1);
  734         if ((ins(port + BankSelect) & BsrMask) != BsrId) {
  735                 outs(port + Control, 0);        /* try powering up the chip */
  736                 delay(55);
  737         }
  738 
  739         outs(port + Config, ins(port + Config) | Cfg16Bit);
  740         x = ins(port + BaseAddr);
  741 
  742         if (((ins(port + BankSelect) & BsrMask) != BsrId) ||
  743                 ((x >> 8) == (x & 0xFF))) {
  744                 iunlock(ctlr);
  745                 iofree(port);
  746                 pcmspecialclose(slot);
  747                 return -1;
  748         }
  749 
  750         SELECT_BANK(3);
  751         ctlr->rev = ins(port + Revision) & 0xFF;
  752 
  753         memset(ea, 0, Eaddrlen);
  754         if (memcmp(ea, ether->ea, Eaddrlen) == 0) {
  755                 if (readnodeid(slot, ether) < 0) {
  756                         print("Smc91cXX: cannot find ethernet address\n");
  757                         iunlock(ctlr);
  758                         iofree(port);
  759                         pcmspecialclose(slot);
  760                         return -1;
  761                 }
  762         }
  763 
  764         chipreset(ether);
  765 
  766         ether->attach = attach;
  767         ether->transmit = transmit;
  768         ether->interrupt = interrupt;
  769         ether->ifstat = ifstat;
  770         ether->promiscuous = promiscuous;
  771         ether->multicast = multicast;
  772         ether->arg = ether;
  773         iunlock(ctlr);
  774         return 0;
  775 }
  776 
  777 void
  778 ethersmclink(void)
  779 {
  780         addethercard("smc91cXX", reset);
  781 }

Cache object: 2591ce0f7007a80b93df5ba75b5395ed


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