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/drivers/dpeth/3c509.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 **  File:       3c509.c         Jun. 01, 2000
    3 **
    4 **  Author:     Giovanni Falzoni <gfalzoni@inwind.it>
    5 **
    6 **  This file contains specific implementation of the ethernet
    7 **  device driver for 3Com Etherlink III (3c509) boards.
    8 **  NOTE: The board has to be setup to disable PnP and to assign
    9 **        I/O base and IRQ.  The driver is for ISA bus only
   10 **
   11 **  $Id: 3c509.c,v 1.3 2005/08/05 19:08:43 beng Exp $
   12 */
   13 
   14 #include "drivers.h"
   15 #include <minix/com.h>
   16 #include <net/hton.h>
   17 #include <net/gen/ether.h>
   18 #include <net/gen/eth_io.h>
   19 
   20 #include "dp.h"
   21 
   22 #if (ENABLE_3C509 == 1)
   23 
   24 #include "3c509.h"
   25 
   26 static const char *const IfNamesMsg[] = {
   27         "10BaseT", "AUI", "unknown", "BNC",
   28 };
   29 
   30 /*
   31 **  Name:       void el3_update_stats(dpeth_t *dep)
   32 **  Function:   Reads statistic counters from board
   33 **              and updates local counters.
   34 */
   35 static void el3_update_stats(dpeth_t * dep)
   36 {
   37 
   38   /* Disables statistics while reading and switches to the correct window */
   39   outw_el3(dep, REG_CmdStatus, CMD_StatsDisable);
   40   SetWindow(WNO_Statistics);
   41 
   42   /* Reads everything, adding values to the local counters */
   43   dep->de_stat.ets_sendErr += inb_el3(dep, REG_TxCarrierLost);  /* Reg. 00 */
   44   dep->de_stat.ets_sendErr += inb_el3(dep, REG_TxNoCD);         /* Reg. 01 */
   45   dep->de_stat.ets_collision += inb_el3(dep, REG_TxMultColl);   /* Reg. 02 */
   46   dep->de_stat.ets_collision += inb_el3(dep, REG_TxSingleColl); /* Reg. 03 */
   47   dep->de_stat.ets_collision += inb_el3(dep, REG_TxLate);       /* Reg. 04 */
   48   dep->de_stat.ets_recvErr += inb_el3(dep, REG_RxDiscarded);    /* Reg. 05 */
   49   dep->de_stat.ets_packetT += inb_el3(dep, REG_TxFrames);       /* Reg. 06 */
   50   dep->de_stat.ets_packetR += inb_el3(dep, REG_RxFrames);       /* Reg. 07 */
   51   dep->de_stat.ets_transDef += inb_el3(dep, REG_TxDefer);       /* Reg. 08 */
   52   dep->bytes_Rx += (unsigned) inw_el3(dep, REG_RxBytes);        /* Reg. 10 */
   53   dep->bytes_Tx += (unsigned) inw_el3(dep, REG_TxBytes);        /* Reg. 12 */
   54 
   55   /* Goes back to operating window and enables statistics */
   56   SetWindow(WNO_Operating);
   57   outw_el3(dep, REG_CmdStatus, CMD_StatsEnable);
   58 
   59   return;
   60 }
   61 
   62 /*
   63 **  Name:       void el3_getstats(dpeth_t *dep)
   64 **  Function:   Reads statistics counters from board.
   65 */
   66 static void el3_getstats(dpeth_t * dep)
   67 {
   68 
   69   lock();
   70   el3_update_stats(dep);
   71   unlock();
   72   return;
   73 }
   74 
   75 /*
   76 **  Name:       void el3_dodump(dpeth_t *dep)
   77 **  Function:   Dumps counter on screen (support for console display).
   78 */
   79 static void el3_dodump(dpeth_t * dep)
   80 {
   81 
   82   el3_getstats(dep);
   83   return;
   84 }
   85 
   86 /*
   87 **  Name:       void el3_rx_mode(dpeth_t *dep)
   88 **  Function:   Initializes receiver mode
   89 */
   90 static void el3_rx_mode(dpeth_t * dep)
   91 {
   92 
   93   dep->de_recv_mode = FilterIndividual;
   94   if (dep->de_flags & DEF_BROAD) dep->de_recv_mode |= FilterBroadcast;
   95   if (dep->de_flags & DEF_MULTI) dep->de_recv_mode |= FilterMulticast;
   96   if (dep->de_flags & DEF_PROMISC) dep->de_recv_mode |= FilterPromiscuous;
   97 
   98   outw_el3(dep, REG_CmdStatus, CMD_RxReset);
   99   outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter | dep->de_recv_mode);
  100   outw_el3(dep, REG_CmdStatus, CMD_RxEnable);
  101 
  102   return;
  103 }
  104 
  105 /*
  106 **  Name:       void el3_reset(dpeth_t *dep)
  107 **  Function:   Reset function specific for Etherlink hardware.
  108 */
  109 static void el3_reset(dpeth_t * dep)
  110 {
  111 
  112   return;                       /* Done */
  113 }
  114 
  115 /*
  116 **  Name:       void el3_write_fifo(dpeth_t * dep, int pktsize);
  117 **  Function:   Writes a packet from user area to board.
  118 **  Remark:     Writing a word/dword at a time may result faster
  119 **              but is a lot more complicated. Let's go simpler way.
  120 */
  121 static void el3_write_fifo(dpeth_t * dep, int pktsize)
  122 {
  123   phys_bytes phys_user;
  124   int bytes, ix = 0;
  125   iovec_dat_t *iovp = &dep->de_write_iovec;
  126   int padding = pktsize;
  127 
  128   do {                          /* Writes chuncks of packet from user buffers */
  129 
  130         bytes = iovp->iod_iovec[ix].iov_size;   /* Size of buffer */
  131         if (bytes > pktsize) bytes = pktsize;
  132         /* Writes from user buffer to Tx FIFO */
  133         outsb(dep->de_data_port, iovp->iod_proc_nr,
  134               (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
  135         if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
  136                 dp_next_iovec(iovp);
  137                 ix = 0;
  138         }
  139         /* Till packet done */
  140   } while ((pktsize -= bytes) > 0);
  141   while ((padding++ % sizeof(long)) != 0) outb(dep->de_data_port, 0x00);
  142   return;
  143 }
  144 
  145 /*
  146 **  Name:       void el3_recv(dpeth_t *dep, int fromint, int size)
  147 **  Function:   Receive function.  Called from interrupt handler or
  148 **              from main to unload recv. buffer (packet to client)
  149 */
  150 static void el3_recv(dpeth_t *dep, int fromint, int size)
  151 {
  152   buff_t *rxptr;
  153 
  154   while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) {
  155 
  156         lock();                 /* Remove buffer from queue */
  157         if (dep->de_recvq_tail == dep->de_recvq_head)
  158                 dep->de_recvq_head = dep->de_recvq_tail = NULL;
  159         else
  160                 dep->de_recvq_head = rxptr->next;
  161         unlock();
  162 
  163         /* Copy buffer to user area and free it */
  164         mem2user(dep, rxptr);
  165 
  166         dep->de_read_s = rxptr->size;
  167         dep->de_flags |= DEF_ACK_RECV;
  168         dep->de_flags &= NOT(DEF_READING);
  169 
  170         /* Return buffer to the idle pool */
  171         free_buff(dep, rxptr);
  172   }
  173   return;
  174 }
  175 
  176 /*
  177 **  Name:       void el3_rx_complete(dpeth_t * dep);
  178 **  Function:   Upon receiving a packet, provides status checks
  179 **              and if packet is OK copies it to local buffer.
  180 */
  181 static void el3_rx_complete(dpeth_t * dep)
  182 {
  183   short int RxStatus;
  184   int pktsize;
  185   buff_t *rxptr;
  186 
  187   RxStatus = inw_el3(dep, REG_RxStatus);
  188   pktsize = RxStatus & RXS_Length;      /* Mask off packet length */
  189 
  190   if (RxStatus & RXS_Error) {
  191 
  192         /* First checks for receiving errors */
  193         RxStatus &= RXS_ErrType;
  194         switch (RxStatus) {     /* Bad packet (see error type) */
  195             case RXS_Dribble:
  196             case RXS_Oversize:
  197             case RXS_Runt:      dep->de_stat.ets_recvErr += 1;  break;
  198             case RXS_Overrun:   dep->de_stat.ets_OVW += 1;      break;
  199             case RXS_Framing:   dep->de_stat.ets_frameAll += 1; break;
  200             case RXS_CRC:       dep->de_stat.ets_CRCerr += 1;   break;
  201         }
  202 
  203   } else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) {
  204         /* Memory not available. Drop packet */
  205         dep->de_stat.ets_fifoOver += 1;
  206 
  207   } else {
  208         /* Good packet.  Read it from FIFO */
  209         insb(dep->de_data_port, SELF, rxptr->buffer, pktsize);
  210         rxptr->next = NULL;
  211         rxptr->size = pktsize;
  212 
  213         lock();                 /* Queue packet to receive queue */
  214         if (dep->de_recvq_head == NULL)
  215                 dep->de_recvq_head = rxptr;
  216         else
  217                 dep->de_recvq_tail->next = rxptr;
  218         dep->de_recvq_tail = rxptr;
  219         unlock();
  220 
  221         /* Reply to pending Receive requests, if any */
  222         el3_recv(dep, TRUE, pktsize);
  223   }
  224 
  225   /* Discard top packet from queue */
  226   outw_el3(dep, REG_CmdStatus, CMD_RxDiscard);
  227 
  228   return;
  229 }
  230 
  231 /*
  232 **  Name:       void el3_send(dpeth_t *dep, int count)
  233 **  Function:   Send function.  Called from main to transit a packet or
  234 **              from interrupt handler when Tx FIFO gets available.
  235 */
  236 static void el3_send(dpeth_t * dep, int from_int, int count)
  237 {
  238   clock_t now;
  239   int ix;
  240   short int TxStatus;
  241 
  242   getuptime(&now);
  243   if ((dep->de_flags & DEF_XMIT_BUSY) &&
  244       (now - dep->de_xmit_start) > 4) {
  245 
  246         DEBUG(printf("3c509:  Transmitter timed out. Resetting ....\n");)
  247         dep->de_stat.ets_sendErr += 1;
  248         /* Resets and restars the transmitter */
  249         outw_el3(dep, REG_CmdStatus, CMD_TxReset);
  250         outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
  251         dep->de_flags &= NOT(DEF_XMIT_BUSY);
  252   }
  253   if (!(dep->de_flags & DEF_XMIT_BUSY)) {
  254 
  255         /* Writes Transmitter preamble 1st Word (packet len, no ints) */
  256         outw_el3(dep, REG_TxFIFO, count);
  257         /* Writes Transmitter preamble 2nd Word (all zero) */
  258         outw_el3(dep, REG_TxFIFO, 0);
  259         /* Writes packet */
  260         el3_write_fifo(dep, count);
  261 
  262         getuptime(&dep->de_xmit_start);
  263         dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
  264         if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) {
  265                 /* Tx has enough room for a packet of maximum size */
  266                 dep->de_flags &= NOT(DEF_XMIT_BUSY | DEF_SENDING);
  267         } else {
  268                 /* Interrupt driver when enough room is available */
  269                 outw_el3(dep, REG_CmdStatus, CMD_SetTxAvailable | ETH_MAX_PACK_SIZE);
  270                 dep->de_flags &= NOT(DEF_SENDING);
  271         }
  272 
  273         /* Pops Tx status stack */
  274         for (ix = 4; --ix && (TxStatus = inb_el3(dep, REG_TxStatus)) > 0;) {
  275                 if (TxStatus & 0x38) dep->de_stat.ets_sendErr += 1;
  276                 if (TxStatus & 0x30)
  277                         outw_el3(dep, REG_CmdStatus, CMD_TxReset);
  278                 if (TxStatus & 0x3C)
  279                         outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
  280                 outb_el3(dep, REG_TxStatus, 0);
  281         }
  282   }
  283   return;
  284 }
  285 
  286 /*
  287 **  Name:       void el3_close(dpeth_t *dep)
  288 **  Function:   Stops board and makes it ready to shut down.
  289 */
  290 static void el3_close(dpeth_t * dep)
  291 {
  292 
  293   /* Disables statistics, Receiver and Transmitter */
  294   outw_el3(dep, REG_CmdStatus, CMD_StatsDisable);
  295   outw_el3(dep, REG_CmdStatus, CMD_RxDisable);
  296   outw_el3(dep, REG_CmdStatus, CMD_TxDisable);
  297 
  298   if (dep->de_if_port == BNC_XCVR) {
  299         outw_el3(dep, REG_CmdStatus, CMD_StopIntXcvr);
  300         /* milli_delay(5); */
  301 
  302   } else if (dep->de_if_port == TP_XCVR) {
  303         SetWindow(WNO_Diagnostics);
  304         outw_el3(dep, REG_MediaStatus, inw_el3(dep, REG_MediaStatus) &
  305                  NOT((MediaLBeatEnable | MediaJabberEnable)));
  306         /* milli_delay(5); */
  307   }
  308   DEBUG(printf("%s: stopping Etherlink ... \n", dep->de_name));
  309   /* Issues a global reset
  310   outw_el3(dep, REG_CmdStatus, CMD_GlobalReset); */
  311   sys_irqdisable(&dep->de_hook);        /* Disable interrupt */
  312  
  313   return;
  314 }
  315 
  316 /*
  317 **  Name:       void el3_interrupt(dpeth_t *dep)
  318 **  Function:   Interrupt handler.  Acknwledges transmit interrupts
  319 **              or unloads receive buffer to memory queue.
  320 */
  321 static void el3_interrupt(dpeth_t * dep)
  322 {
  323   int loop;
  324   unsigned short isr;
  325 
  326   for (loop = 5; loop > 0 && ((isr = inw_el3(dep, REG_CmdStatus)) &
  327          (INT_Latch | INT_RxComplete | INT_UpdateStats)); loop -= 1) {
  328 
  329         if (isr & INT_RxComplete)       /* Got a new packet */
  330                 el3_rx_complete(dep);
  331 
  332         if (isr & INT_TxAvailable) {    /* Tx has room for big packets */
  333                 DEBUG(printf("3c509: got Tx interrupt, Status=0x%04x\n", isr);)
  334                 dep->de_flags &= NOT(DEF_XMIT_BUSY);
  335                 outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_TxAvailable);
  336                 if (dep->de_flags & DEF_SENDING)        /* Send pending */
  337                         el3_send(dep, TRUE, dep->de_send_s);
  338         }
  339         if (isr & (INT_AdapterFail | INT_RxEarly | INT_UpdateStats)) {
  340 
  341                 if (isr & INT_UpdateStats)      /* Empties statistics */
  342                         el3_getstats(dep);
  343 
  344                 if (isr & INT_RxEarly)  /* Not really used. Do nothing */
  345                         outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_RxEarly));
  346 
  347                 if (isr & INT_AdapterFail) {
  348                         /* Adapter error. Reset and re-enable receiver */
  349                         DEBUG(printf("3c509: got Rx fail interrupt, Status=0x%04x\n", isr);)
  350                         el3_rx_mode(dep);
  351                         outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_AdapterFail);
  352                 }
  353         }
  354 
  355         /* Acknowledge interrupt */
  356         outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_Latch | INT_Requested));
  357   }
  358   return;
  359 }
  360 
  361 /*
  362 **  Name:       unsigned el3_read_eeprom(port_t port, unsigned address);
  363 **  Function:   Reads the EEPROM at specified address
  364 */
  365 static unsigned el3_read_eeprom(port_t port, unsigned address)
  366 {
  367   unsigned int result;
  368   int bit;
  369 
  370   address |= EL3_READ_EEPROM;
  371   outb(port, address);
  372   milli_delay(5);               /* Allows EEPROM reads */
  373   for (result = 0, bit = 16; bit > 0; bit -= 1) {
  374         result = (result << 1) | (inb(port) & 0x0001);
  375   }
  376   return result;
  377 }
  378 
  379 /*
  380 **  Name:       void el3_read_StationAddress(dpeth_t *dep)
  381 **  Function:   Reads station address from board
  382 */
  383 static void el3_read_StationAddress(dpeth_t * dep)
  384 {
  385   unsigned int ix, rc;
  386 
  387   for (ix = EE_3COM_NODE_ADDR; ix < SA_ADDR_LEN;) {
  388         /* Accesses with word No. */
  389         rc = el3_read_eeprom(dep->de_id_port, ix / 2);
  390         /* Swaps bytes of word */
  391         dep->de_address.ea_addr[ix++] = (rc >> 8) & 0xFF;
  392         dep->de_address.ea_addr[ix++] = rc & 0xFF;
  393   }
  394   return;
  395 }
  396 
  397 /*
  398 **  Name:       void el3_open(dpeth_t *dep)
  399 **  Function:   Initalizes board hardware and driver data structures.
  400 */
  401 static void el3_open(dpeth_t * dep)
  402 {
  403   unsigned int AddrCfgReg, ResCfgReg;
  404   unsigned int ix;
  405 
  406   el3_read_StationAddress(dep); /* Get ethernet address */
  407 
  408   /* Get address and resource configurations */
  409   AddrCfgReg = el3_read_eeprom(dep->de_id_port, EE_ADDR_CFG);
  410   ResCfgReg = el3_read_eeprom(dep->de_id_port, EE_RESOURCE_CFG);
  411   outb(dep->de_id_port, EL3_ACTIVATE);  /* Activate the board */
  412 
  413   /* Gets xcvr configuration */
  414   dep->de_if_port = AddrCfgReg & EL3_CONFIG_XCVR_MASK;
  415 
  416   AddrCfgReg = ((AddrCfgReg & EL3_CONFIG_IOBASE_MASK) << 4) + EL3_IO_BASE_ADDR;
  417   if (AddrCfgReg != dep->de_base_port)
  418         panic(dep->de_name, "Bad I/O port for Etherlink board", NO_NUM);
  419 
  420   ResCfgReg >>= 12;
  421   dep->de_irq &= NOT(DEI_DEFAULT);      /* Strips the default flag */
  422   if (ResCfgReg != dep->de_irq) panic(dep->de_name, "Bad IRQ for Etherlink board", NO_NUM);
  423 
  424   SetWindow(WNO_Setup);
  425 
  426   /* Reset transmitter and receiver */
  427   outw_el3(dep, REG_CmdStatus, CMD_TxReset);
  428   outw_el3(dep, REG_CmdStatus, CMD_RxReset);
  429 
  430   /* Enable the adapter */
  431   outb_el3(dep, REG_CfgControl, EL3_EnableAdapter);
  432   /* Disable Status bits */
  433   outw_el3(dep, REG_CmdStatus, CMD_SetStatusEnab + 0x00);
  434 
  435   /* Set "my own" address */
  436   SetWindow(WNO_StationAddress);
  437   for (ix = 0; ix < 6; ix += 1)
  438         outb_el3(dep, REG_SA0_1 + ix, dep->de_address.ea_addr[ix]);
  439 
  440   /* Start Transceivers as required */
  441   if (dep->de_if_port == BNC_XCVR) {
  442         /* Start internal transceiver for Coaxial cable */
  443         outw_el3(dep, REG_CmdStatus, CMD_StartIntXcvr);
  444         milli_delay(5);
  445 
  446   } else if (dep->de_if_port == TP_XCVR) {
  447         /* Start internal transceiver for Twisted pair cable */
  448         SetWindow(WNO_Diagnostics);
  449         outw_el3(dep, REG_MediaStatus,
  450                  inw_el3(dep, REG_MediaStatus) | (MediaLBeatEnable | MediaJabberEnable));
  451   }
  452 
  453   /* Switch to the statistic window, and clear counts (by reading) */
  454   SetWindow(WNO_Statistics);
  455   for (ix = REG_TxCarrierLost; ix <= REG_TxDefer; ix += 1) inb_el3(dep, ix);
  456   inw_el3(dep, REG_RxBytes);
  457   inw_el3(dep, REG_TxBytes);
  458 
  459   /* Switch to operating window for normal use */
  460   SetWindow(WNO_Operating);
  461 
  462   /* Receive individual address & broadcast. (Mofified later by rx_mode) */
  463   outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter |
  464          (FilterIndividual | FilterBroadcast));
  465 
  466   /* Turn on statistics */
  467   outw_el3(dep, REG_CmdStatus, CMD_StatsEnable);
  468 
  469   /* Enable transmitter and receiver */
  470   outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
  471   outw_el3(dep, REG_CmdStatus, CMD_RxEnable);
  472 
  473   /* Enable all the status bits */
  474   outw_el3(dep, REG_CmdStatus, CMD_SetStatusEnab | 0xFF);
  475 
  476   /* Acknowledge all interrupts to clear adapter. Enable interrupts */
  477   outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | 0xFF);
  478   outw_el3(dep, REG_CmdStatus, CMD_SetIntMask |
  479     (INT_Latch | INT_TxAvailable | INT_RxComplete | INT_UpdateStats));
  480 
  481   /* Ready to operate, sets the environment for eth_task */
  482   dep->de_data_port = dep->de_base_port;
  483   /* Allocates Rx/Tx buffers */
  484   init_buff(dep, NULL);
  485 
  486   /* Device specific functions */
  487   dep->de_recvf = el3_recv;
  488   dep->de_sendf = el3_send;
  489   dep->de_flagsf = el3_rx_mode;
  490   dep->de_resetf = el3_reset;
  491   dep->de_getstatsf = el3_getstats;
  492   dep->de_dumpstatsf = el3_dodump;
  493   dep->de_interruptf = el3_interrupt;
  494 
  495   printf("%s: Etherlink III (%s) at %X:%d, %s port - ",
  496          dep->de_name, "3c509", dep->de_base_port, dep->de_irq,
  497          IfNamesMsg[dep->de_if_port >> 14]);
  498   for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
  499         printf("%02X%c", dep->de_address.ea_addr[ix],
  500                ix < SA_ADDR_LEN - 1 ? ':' : '\n');
  501 
  502   return;                       /* Done */
  503 }
  504 
  505 /*
  506 **  Name:       unsigned int el3_checksum(port_t port);
  507 **  Function:   Reads EEPROM and computes checksum.
  508 */
  509 static unsigned short el3_checksum(port_t port)
  510 {
  511   unsigned short rc, checksum, address;
  512   unsigned char lo, hi;
  513 
  514   for (checksum = address = 0; address < 15; address += 1) {
  515         rc = el3_read_eeprom(port, address);
  516         lo = rc & 0xFF;
  517         hi = (rc >> 8) & 0xFF;
  518         if ((address == EE_PROD_ID && (rc & EE_PROD_ID_MASK) != EL3_PRODUCT_ID) ||
  519             (address == EE_3COM_CODE && rc != EL3_3COM_CODE))
  520                 return address;
  521         if (address == EE_ADDR_CFG ||
  522             address == EE_RESOURCE_CFG ||
  523             address == EE_SW_CONFIG_INFO) {
  524                 lo ^= hi;
  525                 hi = 0;
  526         } else {
  527                 hi ^= lo;
  528                 lo = 0;
  529         }
  530         rc = ((unsigned) hi << 8) + lo;
  531         checksum ^= rc;
  532   }
  533   rc = el3_read_eeprom(port, address);
  534   return(checksum ^= rc);       /* If OK checksum is 0 */
  535 }
  536 
  537 /*
  538 **  Name:       void el3_write_id(port_t port);
  539 **  Function:   Writes the ID sequence to the board.
  540 */
  541 static void el3_write_id(port_t port)
  542 {
  543   int ix, pattern;
  544 
  545   outb(port, 0);                /* Selects the ID port */
  546   outb(port, 0);                /* Resets hardware pattern generator */
  547   for (pattern = ix = 0x00FF; ix > 0; ix -= 1) {
  548         outb(port, pattern);
  549         pattern <<= 1;
  550         pattern = (pattern & 0x0100) ? pattern ^ 0xCF : pattern;
  551   }
  552   return;
  553 }
  554 
  555 /*
  556 **  Name:       int el3_probe(dpeth_t *dep)
  557 **  Function:   Checks for presence of the board.
  558 */
  559 PUBLIC int el3_probe(dpeth_t * dep)
  560 {
  561   port_t id_port;
  562 
  563   /* Don't ask me what is this for !! */
  564   outb(0x0279, 0x02);   /* Select PnP config control register. */
  565   outb(0x0A79, 0x02);   /* Return to WaitForKey state. */
  566   /* Tests I/O ports in the 0x1xF range for a valid ID port */
  567   for (id_port = 0x110; id_port < 0x200; id_port += 0x10) {
  568         outb(id_port, 0x00);
  569         outb(id_port, 0xFF);
  570         if (inb(id_port) & 0x01) break;
  571   }
  572   if (id_port == 0x200) return 0;       /* No board responding */
  573 
  574   el3_write_id(id_port);
  575   outb(id_port, EL3_ID_GLOBAL_RESET);   /* Reset the board */
  576   milli_delay(5);               /* Technical reference says 162 micro sec. */
  577   el3_write_id(id_port);
  578   outb(id_port, EL3_SET_TAG_REGISTER);
  579   milli_delay(5);
  580 
  581   dep->de_id_port = id_port;    /* Stores ID port No. */
  582   dep->de_ramsize =             /* RAM size is meaningless */
  583         dep->de_offset_page = 0;
  584   dep->de_linmem = 0L;          /* Access is via I/O port  */
  585 
  586   /* Device specific functions */
  587   dep->de_initf = el3_open;
  588   dep->de_stopf = el3_close;
  589 
  590   return(el3_checksum(id_port) == 0);   /* Etherlink board found/not found */
  591 }
  592 
  593 #endif                          /* ENABLE_3C509 */
  594 
  595 /** 3c509.c **/

Cache object: f83ae10571b181cf7ec63f9e92c13b2e


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