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