cs89x0.c

Go to the documentation of this file.
00001 #ifdef ALLMULTI
00002 #error multicast support is not yet implemented
00003 #endif
00004 
00005 /**
00006    Per an email message from Russ Nelson <nelson@crynwr.com> on
00007    18 March 2008 this file is now licensed under GPL Version 2.
00008 
00009    From: Russ Nelson <nelson@crynwr.com>
00010    Date: Tue, 18 Mar 2008 12:42:00 -0400
00011    Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
00012    -- quote from email 
00013    As copyright holder, if I say it doesn't conflict with the GPL,
00014    then it doesn't conflict with the GPL.
00015 
00016    However, there's no point in causing people's brains to overheat,
00017    so yes, I grant permission for the code to be relicensed under the
00018    GPLv2.  Please make sure that this change in licensing makes its
00019    way upstream.  -russ 
00020    -- quote from email
00021 **/
00022 
00023 FILE_LICENCE ( GPL2_ONLY );
00024 
00025 /* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */
00026 /*
00027   Permission is granted to distribute the enclosed cs89x0.[ch] driver
00028   only in conjunction with the Etherboot package.  The code is
00029   ordinarily distributed under the GPL.
00030   
00031   Russ Nelson, January 2000
00032 
00033   ChangeLog:
00034 
00035   Thu Dec 6 22:40:00 1996  Markus Gutschke  <gutschk@math.uni-muenster.de>
00036 
00037   * disabled all "advanced" features; this should make the code more reliable
00038 
00039   * reorganized the reset function
00040 
00041   * always reset the address port, so that autoprobing will continue working
00042 
00043   * some cosmetic changes
00044 
00045   * 2.5
00046 
00047   Thu Dec 5 21:00:00 1996  Markus Gutschke  <gutschk@math.uni-muenster.de>
00048 
00049   * tested the code against a CS8900 card
00050 
00051   * lots of minor bug fixes and adjustments
00052 
00053   * this is the first release, that actually works! it still requires some
00054     changes in order to be more tolerant to different environments
00055 
00056   * 4
00057 
00058   Fri Nov 22 23:00:00 1996  Markus Gutschke  <gutschk@math.uni-muenster.de>
00059 
00060   * read the manuals for the CS89x0 chipsets and took note of all the
00061     changes that will be neccessary in order to adapt Russel Nelson's code
00062     to the requirements of a BOOT-Prom
00063 
00064   * 6
00065 
00066   Thu Nov 19 22:00:00 1996  Markus Gutschke  <gutschk@math.uni-muenster.de>
00067 
00068   * Synched with Russel Nelson's current code (v1.00)
00069 
00070   * 2
00071 
00072   Thu Nov 12 18:00:00 1996  Markus Gutschke  <gutschk@math.uni-muenster.de>
00073 
00074   * Cleaned up some of the code and tried to optimize the code size.
00075 
00076   * 1.5
00077 
00078   Sun Nov 10 16:30:00 1996  Markus Gutschke  <gutschk@math.uni-muenster.de>
00079 
00080   * First experimental release. This code compiles fine, but I
00081   have no way of testing whether it actually works.
00082 
00083   * I did not (yet) bother to make the code 16bit aware, so for
00084   the time being, it will only work for Etherboot/32.
00085 
00086   * 12
00087 
00088   */
00089 
00090 #include <errno.h>
00091 #include <gpxe/ethernet.h>
00092 #include "etherboot.h"
00093 #include "nic.h"
00094 #include <gpxe/isa.h>
00095 #include "console.h"
00096 #include "cs89x0.h"
00097 
00098 static unsigned short   eth_nic_base;
00099 static unsigned long    eth_mem_start;
00100 static unsigned short   eth_irqno;
00101 static unsigned short   eth_cs_type;    /* one of: CS8900, CS8920, CS8920M  */
00102 static unsigned short   eth_auto_neg_cnf;
00103 static unsigned short   eth_adapter_cnf;
00104 static unsigned short   eth_linectl;
00105 
00106 /*************************************************************************
00107         CS89x0 - specific routines
00108 **************************************************************************/
00109 
00110 static inline int readreg(int portno)
00111 {
00112         outw(portno, eth_nic_base + ADD_PORT);
00113         return inw(eth_nic_base + DATA_PORT);
00114 }
00115 
00116 static inline void writereg(int portno, int value)
00117 {
00118         outw(portno, eth_nic_base + ADD_PORT);
00119         outw(value, eth_nic_base + DATA_PORT);
00120         return;
00121 }
00122 
00123 /*************************************************************************
00124 EEPROM access
00125 **************************************************************************/
00126 
00127 static int wait_eeprom_ready(void)
00128 {
00129         unsigned long tmo = currticks() + 4*TICKS_PER_SEC;
00130 
00131         /* check to see if the EEPROM is ready, a timeout is used -
00132            just in case EEPROM is ready when SI_BUSY in the
00133            PP_SelfST is clear */
00134         while(readreg(PP_SelfST) & SI_BUSY) {
00135                 if (currticks() >= tmo)
00136                         return -1; }
00137         return 0;
00138 }
00139 
00140 static int get_eeprom_data(int off, int len, unsigned short *buffer)
00141 {
00142         int i;
00143 
00144 #ifdef  EDEBUG
00145         printf("\ncs: EEPROM data from %hX for %hX:",off,len);
00146 #endif
00147         for (i = 0; i < len; i++) {
00148                 if (wait_eeprom_ready() < 0)
00149                         return -1;
00150                 /* Now send the EEPROM read command and EEPROM location
00151                    to read */
00152                 writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD);
00153                 if (wait_eeprom_ready() < 0)
00154                         return -1;
00155                 buffer[i] = readreg(PP_EEData);
00156 #ifdef  EDEBUG
00157                 if (!(i%10))
00158                         printf("\ncs: ");
00159                 printf("%hX ", buffer[i]);
00160 #endif
00161         }
00162 #ifdef  EDEBUG
00163         putchar('\n');
00164 #endif
00165 
00166         return(0);
00167 }
00168 
00169 static int get_eeprom_chksum(int off __unused, int len, unsigned short *buffer)
00170 {
00171         int  i, cksum;
00172 
00173         cksum = 0;
00174         for (i = 0; i < len; i++)
00175                 cksum += buffer[i];
00176         cksum &= 0xffff;
00177         if (cksum == 0)
00178                 return 0;
00179         return -1;
00180 }
00181 
00182 /*************************************************************************
00183 Activate all of the available media and probe for network
00184 **************************************************************************/
00185 
00186 static void clrline(void)
00187 {
00188         int i;
00189 
00190         putchar('\r');
00191         for (i = 79; i--; ) putchar(' ');
00192         printf("\rcs: ");
00193         return;
00194 }
00195 
00196 static void control_dc_dc(int on_not_off)
00197 {
00198         unsigned int selfcontrol;
00199         unsigned long tmo = currticks() + TICKS_PER_SEC;
00200 
00201         /* control the DC to DC convertor in the SelfControl register.  */
00202         selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
00203         if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
00204                 selfcontrol |= HCB1;
00205         else
00206                 selfcontrol &= ~HCB1;
00207         writereg(PP_SelfCTL, selfcontrol);
00208 
00209         /* Wait for the DC/DC converter to power up - 1000ms */
00210         while (currticks() < tmo);
00211 
00212         return;
00213 }
00214 
00215 static int detect_tp(void)
00216 {
00217         unsigned long tmo;
00218 
00219         /* Turn on the chip auto detection of 10BT/ AUI */
00220 
00221         clrline(); printf("attempting %s:","TP");
00222 
00223         /* If connected to another full duplex capable 10-Base-T card
00224            the link pulses seem to be lost when the auto detect bit in
00225            the LineCTL is set.  To overcome this the auto detect bit
00226            will be cleared whilst testing the 10-Base-T interface.
00227            This would not be necessary for the sparrow chip but is
00228            simpler to do it anyway. */
00229         writereg(PP_LineCTL, eth_linectl &~ AUI_ONLY);
00230         control_dc_dc(0);
00231 
00232         /* Delay for the hardware to work out if the TP cable is
00233            present - 150ms */
00234         for (tmo = currticks() + 4; currticks() < tmo; );
00235 
00236         if ((readreg(PP_LineST) & LINK_OK) == 0)
00237                 return 0;
00238 
00239         if (eth_cs_type != CS8900) {
00240 
00241                 writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK);
00242 
00243                 if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
00244                         printf(" negotiating duplex... ");
00245                         while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) {
00246                                 if (currticks() - tmo > 40*TICKS_PER_SEC) {
00247                                         printf("time out ");
00248                                         break;
00249                                 }
00250                         }
00251                 }
00252                 if (readreg(PP_AutoNegST) & FDX_ACTIVE)
00253                         printf("using full duplex");
00254                 else
00255                         printf("using half duplex");
00256         }
00257 
00258         return A_CNF_MEDIA_10B_T;
00259 }
00260 
00261 /* send a test packet - return true if carrier bits are ok */
00262 static int send_test_pkt(struct nic *nic)
00263 {
00264         static unsigned char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
00265                                      0, 46, /*A 46 in network order       */
00266                                      0, 0,  /*DSAP=0 & SSAP=0 fields      */
00267                                      0xf3,0 /*Control (Test Req+P bit set)*/ };
00268         unsigned long tmo;
00269 
00270         writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON);
00271 
00272         memcpy(testpacket, nic->node_addr, ETH_ALEN);
00273         memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN);
00274 
00275         outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
00276         outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT);
00277 
00278         /* Test to see if the chip has allocated memory for the packet */
00279         for (tmo = currticks() + 2;
00280              (readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; )
00281                 if (currticks() >= tmo)
00282                         return(0);
00283 
00284         /* Write the contents of the packet */
00285         outsw(eth_nic_base + TX_FRAME_PORT, testpacket,
00286               (ETH_ZLEN+1)>>1);
00287 
00288         printf(" sending test packet ");
00289         /* wait a couple of timer ticks for packet to be received */
00290         for (tmo = currticks() + 2; currticks() < tmo; );
00291 
00292         if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
00293                         printf("succeeded");
00294                         return 1;
00295         }
00296         printf("failed");
00297         return 0;
00298 }
00299 
00300 
00301 static int detect_aui(struct nic *nic)
00302 {
00303         clrline(); printf("attempting %s:","AUI");
00304         control_dc_dc(0);
00305 
00306         writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
00307 
00308         if (send_test_pkt(nic)) {
00309                 return A_CNF_MEDIA_AUI; }
00310         else
00311                 return 0;
00312 }
00313 
00314 static int detect_bnc(struct nic *nic)
00315 {
00316         clrline(); printf("attempting %s:","BNC");
00317         control_dc_dc(1);
00318 
00319         writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
00320 
00321         if (send_test_pkt(nic)) {
00322                 return A_CNF_MEDIA_10B_2; }
00323         else
00324                 return 0;
00325 }
00326 
00327 /**************************************************************************
00328 ETH_RESET - Reset adapter
00329 ***************************************************************************/
00330 
00331 static void cs89x0_reset(struct nic *nic)
00332 {
00333         int  i;
00334         unsigned long reset_tmo;
00335 
00336         writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET);
00337 
00338         /* wait for two ticks; that is 2*55ms */
00339         for (reset_tmo = currticks() + 2; currticks() < reset_tmo; );
00340 
00341         if (eth_cs_type != CS8900) {
00342                 /* Hardware problem requires PNP registers to be reconfigured
00343                    after a reset */
00344                 if (eth_irqno != 0xFFFF) {
00345                         outw(PP_CS8920_ISAINT, eth_nic_base + ADD_PORT);
00346                         outb(eth_irqno, eth_nic_base + DATA_PORT);
00347                         outb(0, eth_nic_base + DATA_PORT + 1); }
00348 
00349                 if (eth_mem_start) {
00350                         outw(PP_CS8920_ISAMemB, eth_nic_base + ADD_PORT);
00351                         outb((eth_mem_start >> 8) & 0xff, eth_nic_base + DATA_PORT);
00352                         outb((eth_mem_start >> 24) & 0xff, eth_nic_base + DATA_PORT + 1); } }
00353 
00354         /* Wait until the chip is reset */
00355         for (reset_tmo = currticks() + 2;
00356              (readreg(PP_SelfST) & INIT_DONE) == 0 &&
00357                      currticks() < reset_tmo; );
00358 
00359         /* disable interrupts and memory accesses */
00360         writereg(PP_BusCTL, 0);
00361 
00362         /* set the ethernet address */
00363         for (i=0; i < ETH_ALEN/2; i++)
00364                 writereg(PP_IA+i*2,
00365                          nic->node_addr[i*2] |
00366                          (nic->node_addr[i*2+1] << 8));
00367 
00368         /* receive only error free packets addressed to this card */
00369         writereg(PP_RxCTL, DEF_RX_ACCEPT);
00370 
00371         /* do not generate any interrupts on receive operations */
00372         writereg(PP_RxCFG, 0);
00373 
00374         /* do not generate any interrupts on transmit operations */
00375         writereg(PP_TxCFG, 0);
00376 
00377         /* do not generate any interrupts on buffer operations */
00378         writereg(PP_BufCFG, 0);
00379 
00380         /* reset address port, so that autoprobing will keep working */
00381         outw(PP_ChipID, eth_nic_base + ADD_PORT);
00382 
00383         return;
00384 }
00385 
00386 /**************************************************************************
00387 ETH_TRANSMIT - Transmit a frame
00388 ***************************************************************************/
00389 
00390 static void cs89x0_transmit(
00391         struct nic *nic,
00392         const char *d,                  /* Destination */
00393         unsigned int t,                 /* Type */
00394         unsigned int s,                 /* size */
00395         const char *p)                  /* Packet */
00396 {
00397         unsigned long tmo;
00398         int           sr;
00399 
00400         /* does this size have to be rounded??? please,
00401            somebody have a look in the specs */
00402         if ((sr = ((s + ETH_HLEN + 1)&~1)) < ETH_ZLEN)
00403                 sr = ETH_ZLEN;
00404 
00405 retry:
00406         /* initiate a transmit sequence */
00407         outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
00408         outw(sr, eth_nic_base + TX_LEN_PORT);
00409 
00410         /* Test to see if the chip has allocated memory for the packet */
00411         if ((readreg(PP_BusST) & READY_FOR_TX_NOW) == 0) {
00412                 /* Oops... this should not happen! */
00413                 printf("cs: unable to send packet; retrying...\n");
00414                 for (tmo = currticks() + 5*TICKS_PER_SEC; currticks() < tmo; );
00415                 cs89x0_reset(nic);
00416                 goto retry; }
00417 
00418         /* Write the contents of the packet */
00419         outsw(eth_nic_base + TX_FRAME_PORT, d, ETH_ALEN/2);
00420         outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr,
00421               ETH_ALEN/2);
00422         outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
00423         outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
00424         for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--)
00425                 outw(0, eth_nic_base + TX_FRAME_PORT);
00426 
00427         /* wait for transfer to succeed */
00428         for (tmo = currticks()+5*TICKS_PER_SEC;
00429              (s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() < tmo;)
00430                 /* nothing */ ;
00431         if ((s & TX_SEND_OK_BITS) != TX_OK) {
00432                 printf("\ntransmission error %#hX\n", s);
00433         }
00434 
00435         return;
00436 }
00437 
00438 /**************************************************************************
00439 ETH_POLL - Wait for a frame
00440 ***************************************************************************/
00441 
00442 static int cs89x0_poll(struct nic *nic, int retrieve)
00443 {
00444         int status;
00445 
00446         status = readreg(PP_RxEvent);
00447 
00448         if ((status & RX_OK) == 0)
00449                 return(0);
00450 
00451         if ( ! retrieve ) return 1;
00452 
00453         status = inw(eth_nic_base + RX_FRAME_PORT);
00454         nic->packetlen = inw(eth_nic_base + RX_FRAME_PORT);
00455         insw(eth_nic_base + RX_FRAME_PORT, nic->packet, nic->packetlen >> 1);
00456         if (nic->packetlen & 1)
00457                 nic->packet[nic->packetlen-1] = inw(eth_nic_base + RX_FRAME_PORT);
00458         return 1;
00459 }
00460 
00461 static void cs89x0_irq(struct nic *nic __unused, irq_action_t action __unused)
00462 {
00463   switch ( action ) {
00464   case DISABLE :
00465     break;
00466   case ENABLE :
00467     break;
00468   case FORCE :
00469     break;
00470   }
00471 }
00472 
00473 static struct nic_operations cs89x0_operations = {
00474         .connect        = dummy_connect,
00475         .poll           = cs89x0_poll,
00476         .transmit       = cs89x0_transmit,
00477         .irq            = cs89x0_irq,
00478 };
00479 
00480 /**************************************************************************
00481 ETH_PROBE - Look for an adapter
00482 ***************************************************************************/
00483 
00484 static int cs89x0_probe_addr ( isa_probe_addr_t ioaddr ) {
00485         /* if they give us an odd I/O address, then do ONE write to
00486            the address port, to get it back to address zero, where we
00487            expect to find the EISA signature word. */
00488         if (ioaddr & 1) {
00489                 ioaddr &= ~1;
00490                 if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
00491                         return 0;
00492                 outw(PP_ChipID, ioaddr + ADD_PORT);
00493         }
00494         
00495         if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
00496                 return 0;
00497 
00498         return 1;
00499 }
00500 
00501 static int cs89x0_probe ( struct nic *nic, struct isa_device *isa __unused ) {
00502         int      i, result = -1;
00503         unsigned rev_type = 0, isa_cnf, cs_revision;
00504         unsigned short eeprom_buff[CHKSUM_LEN];
00505 
00506         nic->ioaddr &= ~1; /* LSB = 1 indicates a more aggressive probe */
00507         eth_nic_base = nic->ioaddr;
00508 
00509         /* get the chip type */
00510         rev_type = readreg(PRODUCT_ID_ADD);
00511         eth_cs_type = rev_type &~ REVISON_BITS;
00512         cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
00513         
00514         printf("\ncs: cs89%c0%s rev %c, base %#hX",
00515                eth_cs_type==CS8900?'0':'2',
00516                eth_cs_type==CS8920M?"M":"",
00517                cs_revision,
00518                eth_nic_base);
00519 #ifndef EMBEDDED 
00520         /* First check to see if an EEPROM is attached*/
00521         if ((readreg(PP_SelfST) & EEPROM_PRESENT) == 0) {
00522                 printf("\ncs: no EEPROM...\n");
00523                 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00524                 return 0;
00525         } else if (get_eeprom_data(START_EEPROM_DATA,CHKSUM_LEN,
00526                                    eeprom_buff) < 0) {
00527                 printf("\ncs: EEPROM read failed...\n");
00528                 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00529                 return 0;
00530         } else if (get_eeprom_chksum(START_EEPROM_DATA,CHKSUM_LEN,
00531                                      eeprom_buff) < 0) {
00532                 printf("\ncs: EEPROM checksum bad...\n");
00533                 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00534                 return 0;
00535         }
00536 
00537         /* get transmission control word but keep the
00538            autonegotiation bits */
00539         eth_auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
00540         /* Store adapter configuration */
00541         eth_adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
00542         /* Store ISA configuration */
00543         isa_cnf = eeprom_buff[ISA_CNF_OFFSET/2];
00544         
00545         /* store the initial memory base address */
00546         eth_mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
00547         
00548         printf("%s%s%s, addr ",
00549                (eth_adapter_cnf & A_CNF_10B_T)?", RJ-45":"",
00550                (eth_adapter_cnf & A_CNF_AUI)?", AUI":"",
00551                (eth_adapter_cnf & A_CNF_10B_2)?", BNC":"");
00552         
00553         /* If this is a CS8900 then no pnp soft */
00554         if (eth_cs_type != CS8900 &&
00555             /* Check if the ISA IRQ has been set  */
00556             (i = readreg(PP_CS8920_ISAINT) & 0xff,
00557              (i != 0 && i < CS8920_NO_INTS)))
00558                 eth_irqno = i;
00559         else {
00560                 i = isa_cnf & INT_NO_MASK;
00561                 if (eth_cs_type == CS8900) {
00562                         /* the table that follows is dependent
00563                            upon how you wired up your cs8900
00564                            in your system.  The table is the
00565                            same as the cs8900 engineering demo
00566                            board.  irq_map also depends on the
00567                            contents of the table.  Also see
00568                            write_irq, which is the reverse
00569                            mapping of the table below. */
00570                         if (i < 4) i = "\012\013\014\005"[i];
00571                         else printf("\ncs: BUG: isa_config is %d\n", i); }
00572                 eth_irqno = i; }
00573         
00574         nic->irqno = eth_irqno;
00575 
00576         /* Retrieve and print the ethernet address. */
00577         for (i=0; i<ETH_ALEN; i++) {
00578                 nic->node_addr[i] = ((unsigned char *)eeprom_buff)[i];
00579         }
00580 
00581         DBG ( "%s\n", eth_ntoa ( nic->node_addr ) );
00582 
00583 #endif
00584 #ifdef EMBEDDED
00585         /* Retrieve and print the ethernet address. */
00586         {
00587                 unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
00588                 memcpy(nic->node_addr, MAC_HW_ADDR, 6);
00589         }
00590 
00591         DBG ( "%s\n", eth_ntoa ( nic->node_addr ) );
00592         
00593         eth_adapter_cnf = A_CNF_10B_T | A_CNF_MEDIA_10B_T;
00594         eth_auto_neg_cnf = EE_AUTO_NEG_ENABLE | IMM_BIT;
00595 #endif
00596 #ifndef EMBEDDED 
00597         /* Set the LineCTL quintuplet based on adapter
00598            configuration read from EEPROM */
00599         if ((eth_adapter_cnf & A_CNF_EXTND_10B_2) &&
00600             (eth_adapter_cnf & A_CNF_LOW_RX_SQUELCH))
00601                 eth_linectl = LOW_RX_SQUELCH;
00602         else
00603                 eth_linectl = 0;
00604         
00605         /* check to make sure that they have the "right"
00606            hardware available */
00607         switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
00608         case A_CNF_MEDIA_10B_T: result = eth_adapter_cnf & A_CNF_10B_T;
00609                 break;
00610         case A_CNF_MEDIA_AUI:   result = eth_adapter_cnf & A_CNF_AUI;
00611                 break;
00612         case A_CNF_MEDIA_10B_2: result = eth_adapter_cnf & A_CNF_10B_2;
00613                 break;
00614         default: result = eth_adapter_cnf & (A_CNF_10B_T | A_CNF_AUI |
00615                                              A_CNF_10B_2);
00616         }
00617         if (!result) {
00618                 printf("cs: EEPROM is configured for unavailable media\n");
00619         error:
00620                 writereg(PP_LineCTL, readreg(PP_LineCTL) &
00621                          ~(SERIAL_TX_ON | SERIAL_RX_ON));
00622                 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00623                 return 0;
00624         }
00625 #endif
00626         /* Initialize the card for probing of the attached media */
00627         cs89x0_reset(nic);
00628         
00629         /* set the hardware to the configured choice */
00630         switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
00631         case A_CNF_MEDIA_10B_T:
00632                 result = detect_tp();
00633                 if (!result) {
00634                         clrline();
00635                         printf("10Base-T (RJ-45%s",
00636                                ") has no cable\n"); }
00637                 /* check "ignore missing media" bit */
00638                 if (eth_auto_neg_cnf & IMM_BIT)
00639                         /* Yes! I don't care if I see a link pulse */
00640                         result = A_CNF_MEDIA_10B_T;
00641                 break;
00642         case A_CNF_MEDIA_AUI:
00643                 result = detect_aui(nic);
00644                 if (!result) {
00645                         clrline();
00646                         printf("10Base-5 (AUI%s",
00647                                ") has no cable\n"); }
00648                 /* check "ignore missing media" bit */
00649                 if (eth_auto_neg_cnf & IMM_BIT)
00650                         /* Yes! I don't care if I see a carrrier */
00651                         result = A_CNF_MEDIA_AUI;
00652                 break;
00653         case A_CNF_MEDIA_10B_2:
00654                 result = detect_bnc(nic);
00655                 if (!result) {
00656                         clrline();
00657                         printf("10Base-2 (BNC%s",
00658                                ") has no cable\n"); }
00659                 /* check "ignore missing media" bit */
00660                 if (eth_auto_neg_cnf & IMM_BIT)
00661                         /* Yes! I don't care if I can xmit a packet */
00662                         result = A_CNF_MEDIA_10B_2;
00663                 break;
00664         case A_CNF_MEDIA_AUTO:
00665                 writereg(PP_LineCTL, eth_linectl | AUTO_AUI_10BASET);
00666                 if (eth_adapter_cnf & A_CNF_10B_T)
00667                         if ((result = detect_tp()) != 0)
00668                                 break;
00669                 if (eth_adapter_cnf & A_CNF_AUI)
00670                         if ((result = detect_aui(nic)) != 0)
00671                                 break;
00672                 if (eth_adapter_cnf & A_CNF_10B_2)
00673                         if ((result = detect_bnc(nic)) != 0)
00674                                 break;
00675                 clrline(); printf("no media detected\n");
00676                 goto error;
00677         }
00678         clrline();
00679         switch(result) {
00680         case 0:                 printf("no network cable attached to configured media\n");
00681                 goto error;
00682         case A_CNF_MEDIA_10B_T: printf("using 10Base-T (RJ-45)\n");
00683                 break;
00684         case A_CNF_MEDIA_AUI:   printf("using 10Base-5 (AUI)\n");
00685                 break;
00686         case A_CNF_MEDIA_10B_2: printf("using 10Base-2 (BNC)\n");
00687                 break;
00688         }
00689         
00690         /* Turn on both receive and transmit operations */
00691         writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON |
00692                  SERIAL_TX_ON);
00693         
00694         return 0;
00695 #ifdef EMBEDDED
00696  error:
00697         writereg(PP_LineCTL, readreg(PP_LineCTL) &
00698                  ~(SERIAL_TX_ON | SERIAL_RX_ON));
00699         outw(PP_ChipID, eth_nic_base + ADD_PORT);
00700         return 0;
00701 #endif
00702 
00703         nic->nic_op   = &cs89x0_operations;
00704         return 1;
00705 }
00706 
00707 static void cs89x0_disable ( struct nic *nic,
00708                              struct isa_device *isa __unused ) {
00709         cs89x0_reset(nic);
00710 }
00711         
00712 static isa_probe_addr_t cs89x0_probe_addrs[] = { 
00713 #ifndef EMBEDDED
00714         /* use "conservative" default values for autoprobing */
00715         0x300, 0x320, 0x340, 0x200, 0x220, 0x240,
00716         0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
00717         /* if that did not work, then be more aggressive */
00718         0x301, 0x321, 0x341, 0x201, 0x221, 0x241,
00719         0x261, 0x281, 0x2a1, 0x2c1, 0x2e1,
00720 #else
00721         0x01000300,
00722 #endif
00723 };
00724 
00725 ISA_DRIVER ( cs89x0_driver, cs89x0_probe_addrs, cs89x0_probe_addr,
00726              ISAPNP_VENDOR('C','S','C'), 0x0007 );
00727 
00728 DRIVER ( "cs89x0", nic_driver, isa_driver, cs89x0_driver,
00729          cs89x0_probe, cs89x0_disable );
00730 
00731 ISA_ROM ( "cs89x0", "Crystal Semiconductor CS89x0" );
00732 
00733 /*
00734  * Local variables:
00735  *  c-basic-offset: 8
00736  *  c-indent-level: 8
00737  *  tab-width: 8
00738  * End:
00739  */

Generated on Tue Apr 6 20:00:56 2010 for gPXE by  doxygen 1.5.7.1