Home | History | Annotate | Download | only in net
      1 #ifdef ALLMULTI
      2 #error multicast support is not yet implemented
      3 #endif
      4 
      5 /**
      6    Per an email message from Russ Nelson <nelson (at) crynwr.com> on
      7    18 March 2008 this file is now licensed under GPL Version 2.
      8 
      9    From: Russ Nelson <nelson (at) crynwr.com>
     10    Date: Tue, 18 Mar 2008 12:42:00 -0400
     11    Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
     12    -- quote from email
     13    As copyright holder, if I say it doesn't conflict with the GPL,
     14    then it doesn't conflict with the GPL.
     15 
     16    However, there's no point in causing people's brains to overheat,
     17    so yes, I grant permission for the code to be relicensed under the
     18    GPLv2.  Please make sure that this change in licensing makes its
     19    way upstream.  -russ
     20    -- quote from email
     21 **/
     22 
     23 FILE_LICENCE ( GPL2_ONLY );
     24 
     25 /* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */
     26 /*
     27   Permission is granted to distribute the enclosed cs89x0.[ch] driver
     28   only in conjunction with the Etherboot package.  The code is
     29   ordinarily distributed under the GPL.
     30 
     31   Russ Nelson, January 2000
     32 
     33   ChangeLog:
     34 
     35   Thu Dec 6 22:40:00 1996  Markus Gutschke  <gutschk (at) math.uni-muenster.de>
     36 
     37   * disabled all "advanced" features; this should make the code more reliable
     38 
     39   * reorganized the reset function
     40 
     41   * always reset the address port, so that autoprobing will continue working
     42 
     43   * some cosmetic changes
     44 
     45   * 2.5
     46 
     47   Thu Dec 5 21:00:00 1996  Markus Gutschke  <gutschk (at) math.uni-muenster.de>
     48 
     49   * tested the code against a CS8900 card
     50 
     51   * lots of minor bug fixes and adjustments
     52 
     53   * this is the first release, that actually works! it still requires some
     54     changes in order to be more tolerant to different environments
     55 
     56   * 4
     57 
     58   Fri Nov 22 23:00:00 1996  Markus Gutschke  <gutschk (at) math.uni-muenster.de>
     59 
     60   * read the manuals for the CS89x0 chipsets and took note of all the
     61     changes that will be neccessary in order to adapt Russel Nelson's code
     62     to the requirements of a BOOT-Prom
     63 
     64   * 6
     65 
     66   Thu Nov 19 22:00:00 1996  Markus Gutschke  <gutschk (at) math.uni-muenster.de>
     67 
     68   * Synched with Russel Nelson's current code (v1.00)
     69 
     70   * 2
     71 
     72   Thu Nov 12 18:00:00 1996  Markus Gutschke  <gutschk (at) math.uni-muenster.de>
     73 
     74   * Cleaned up some of the code and tried to optimize the code size.
     75 
     76   * 1.5
     77 
     78   Sun Nov 10 16:30:00 1996  Markus Gutschke  <gutschk (at) math.uni-muenster.de>
     79 
     80   * First experimental release. This code compiles fine, but I
     81   have no way of testing whether it actually works.
     82 
     83   * I did not (yet) bother to make the code 16bit aware, so for
     84   the time being, it will only work for Etherboot/32.
     85 
     86   * 12
     87 
     88   */
     89 
     90 #include <errno.h>
     91 #include <gpxe/ethernet.h>
     92 #include "etherboot.h"
     93 #include "nic.h"
     94 #include <gpxe/isa.h>
     95 #include "console.h"
     96 #include "cs89x0.h"
     97 
     98 static unsigned short	eth_nic_base;
     99 static unsigned long    eth_mem_start;
    100 static unsigned short   eth_irqno;
    101 static unsigned short   eth_cs_type;	/* one of: CS8900, CS8920, CS8920M  */
    102 static unsigned short   eth_auto_neg_cnf;
    103 static unsigned short   eth_adapter_cnf;
    104 static unsigned short	eth_linectl;
    105 
    106 /*************************************************************************
    107 	CS89x0 - specific routines
    108 **************************************************************************/
    109 
    110 static inline int readreg(int portno)
    111 {
    112 	outw(portno, eth_nic_base + ADD_PORT);
    113 	return inw(eth_nic_base + DATA_PORT);
    114 }
    115 
    116 static inline void writereg(int portno, int value)
    117 {
    118 	outw(portno, eth_nic_base + ADD_PORT);
    119 	outw(value, eth_nic_base + DATA_PORT);
    120 	return;
    121 }
    122 
    123 /*************************************************************************
    124 EEPROM access
    125 **************************************************************************/
    126 
    127 static int wait_eeprom_ready(void)
    128 {
    129 	unsigned long tmo = currticks() + 4*TICKS_PER_SEC;
    130 
    131 	/* check to see if the EEPROM is ready, a timeout is used -
    132 	   just in case EEPROM is ready when SI_BUSY in the
    133 	   PP_SelfST is clear */
    134 	while(readreg(PP_SelfST) & SI_BUSY) {
    135 		if (currticks() >= tmo)
    136 			return -1; }
    137 	return 0;
    138 }
    139 
    140 static int get_eeprom_data(int off, int len, unsigned short *buffer)
    141 {
    142 	int i;
    143 
    144 #ifdef	EDEBUG
    145 	printf("\ncs: EEPROM data from %hX for %hX:",off,len);
    146 #endif
    147 	for (i = 0; i < len; i++) {
    148 		if (wait_eeprom_ready() < 0)
    149 			return -1;
    150 		/* Now send the EEPROM read command and EEPROM location
    151 		   to read */
    152 		writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD);
    153 		if (wait_eeprom_ready() < 0)
    154 			return -1;
    155 		buffer[i] = readreg(PP_EEData);
    156 #ifdef	EDEBUG
    157 		if (!(i%10))
    158 			printf("\ncs: ");
    159 		printf("%hX ", buffer[i]);
    160 #endif
    161 	}
    162 #ifdef	EDEBUG
    163 	putchar('\n');
    164 #endif
    165 
    166 	return(0);
    167 }
    168 
    169 static int get_eeprom_chksum(int off __unused, int len, unsigned short *buffer)
    170 {
    171 	int  i, cksum;
    172 
    173 	cksum = 0;
    174 	for (i = 0; i < len; i++)
    175 		cksum += buffer[i];
    176 	cksum &= 0xffff;
    177 	if (cksum == 0)
    178 		return 0;
    179 	return -1;
    180 }
    181 
    182 /*************************************************************************
    183 Activate all of the available media and probe for network
    184 **************************************************************************/
    185 
    186 static void clrline(void)
    187 {
    188 	int i;
    189 
    190 	putchar('\r');
    191 	for (i = 79; i--; ) putchar(' ');
    192 	printf("\rcs: ");
    193 	return;
    194 }
    195 
    196 static void control_dc_dc(int on_not_off)
    197 {
    198 	unsigned int selfcontrol;
    199 	unsigned long tmo = currticks() + TICKS_PER_SEC;
    200 
    201 	/* control the DC to DC convertor in the SelfControl register.  */
    202 	selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
    203 	if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
    204 		selfcontrol |= HCB1;
    205 	else
    206 		selfcontrol &= ~HCB1;
    207 	writereg(PP_SelfCTL, selfcontrol);
    208 
    209 	/* Wait for the DC/DC converter to power up - 1000ms */
    210 	while (currticks() < tmo);
    211 
    212 	return;
    213 }
    214 
    215 static int detect_tp(void)
    216 {
    217 	unsigned long tmo;
    218 
    219 	/* Turn on the chip auto detection of 10BT/ AUI */
    220 
    221 	clrline(); printf("attempting %s:","TP");
    222 
    223         /* If connected to another full duplex capable 10-Base-T card
    224 	   the link pulses seem to be lost when the auto detect bit in
    225 	   the LineCTL is set.  To overcome this the auto detect bit
    226 	   will be cleared whilst testing the 10-Base-T interface.
    227 	   This would not be necessary for the sparrow chip but is
    228 	   simpler to do it anyway. */
    229 	writereg(PP_LineCTL, eth_linectl &~ AUI_ONLY);
    230 	control_dc_dc(0);
    231 
    232         /* Delay for the hardware to work out if the TP cable is
    233 	   present - 150ms */
    234 	for (tmo = currticks() + 4; currticks() < tmo; );
    235 
    236 	if ((readreg(PP_LineST) & LINK_OK) == 0)
    237 		return 0;
    238 
    239 	if (eth_cs_type != CS8900) {
    240 
    241 		writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK);
    242 
    243 		if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
    244 			printf(" negotiating duplex... ");
    245 			while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) {
    246 				if (currticks() - tmo > 40*TICKS_PER_SEC) {
    247 					printf("time out ");
    248 					break;
    249 				}
    250 			}
    251 		}
    252 		if (readreg(PP_AutoNegST) & FDX_ACTIVE)
    253 			printf("using full duplex");
    254 		else
    255 			printf("using half duplex");
    256 	}
    257 
    258 	return A_CNF_MEDIA_10B_T;
    259 }
    260 
    261 /* send a test packet - return true if carrier bits are ok */
    262 static int send_test_pkt(struct nic *nic)
    263 {
    264 	static unsigned char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
    265 				     0, 46, /*A 46 in network order       */
    266 				     0, 0,  /*DSAP=0 & SSAP=0 fields      */
    267 				     0xf3,0 /*Control (Test Req+P bit set)*/ };
    268 	unsigned long tmo;
    269 
    270 	writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON);
    271 
    272 	memcpy(testpacket, nic->node_addr, ETH_ALEN);
    273 	memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN);
    274 
    275 	outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
    276 	outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT);
    277 
    278 	/* Test to see if the chip has allocated memory for the packet */
    279 	for (tmo = currticks() + 2;
    280 	     (readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; )
    281 		if (currticks() >= tmo)
    282 			return(0);
    283 
    284 	/* Write the contents of the packet */
    285 	outsw(eth_nic_base + TX_FRAME_PORT, testpacket,
    286 	      (ETH_ZLEN+1)>>1);
    287 
    288 	printf(" sending test packet ");
    289 	/* wait a couple of timer ticks for packet to be received */
    290 	for (tmo = currticks() + 2; currticks() < tmo; );
    291 
    292 	if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
    293 			printf("succeeded");
    294 			return 1;
    295 	}
    296 	printf("failed");
    297 	return 0;
    298 }
    299 
    300 
    301 static int detect_aui(struct nic *nic)
    302 {
    303 	clrline(); printf("attempting %s:","AUI");
    304 	control_dc_dc(0);
    305 
    306 	writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
    307 
    308 	if (send_test_pkt(nic)) {
    309 		return A_CNF_MEDIA_AUI; }
    310 	else
    311 		return 0;
    312 }
    313 
    314 static int detect_bnc(struct nic *nic)
    315 {
    316 	clrline(); printf("attempting %s:","BNC");
    317 	control_dc_dc(1);
    318 
    319 	writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
    320 
    321 	if (send_test_pkt(nic)) {
    322 		return A_CNF_MEDIA_10B_2; }
    323 	else
    324 		return 0;
    325 }
    326 
    327 /**************************************************************************
    328 ETH_RESET - Reset adapter
    329 ***************************************************************************/
    330 
    331 static void cs89x0_reset(struct nic *nic)
    332 {
    333 	int  i;
    334 	unsigned long reset_tmo;
    335 
    336 	writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET);
    337 
    338 	/* wait for two ticks; that is 2*55ms */
    339 	for (reset_tmo = currticks() + 2; currticks() < reset_tmo; );
    340 
    341 	if (eth_cs_type != CS8900) {
    342 		/* Hardware problem requires PNP registers to be reconfigured
    343 		   after a reset */
    344 		if (eth_irqno != 0xFFFF) {
    345 			outw(PP_CS8920_ISAINT, eth_nic_base + ADD_PORT);
    346 			outb(eth_irqno, eth_nic_base + DATA_PORT);
    347 			outb(0, eth_nic_base + DATA_PORT + 1); }
    348 
    349 		if (eth_mem_start) {
    350 			outw(PP_CS8920_ISAMemB, eth_nic_base + ADD_PORT);
    351 			outb((eth_mem_start >> 8) & 0xff, eth_nic_base + DATA_PORT);
    352 			outb((eth_mem_start >> 24) & 0xff, eth_nic_base + DATA_PORT + 1); } }
    353 
    354 	/* Wait until the chip is reset */
    355 	for (reset_tmo = currticks() + 2;
    356 	     (readreg(PP_SelfST) & INIT_DONE) == 0 &&
    357 		     currticks() < reset_tmo; );
    358 
    359 	/* disable interrupts and memory accesses */
    360 	writereg(PP_BusCTL, 0);
    361 
    362 	/* set the ethernet address */
    363 	for (i=0; i < ETH_ALEN/2; i++)
    364 		writereg(PP_IA+i*2,
    365 			 nic->node_addr[i*2] |
    366 			 (nic->node_addr[i*2+1] << 8));
    367 
    368 	/* receive only error free packets addressed to this card */
    369 	writereg(PP_RxCTL, DEF_RX_ACCEPT);
    370 
    371 	/* do not generate any interrupts on receive operations */
    372 	writereg(PP_RxCFG, 0);
    373 
    374 	/* do not generate any interrupts on transmit operations */
    375 	writereg(PP_TxCFG, 0);
    376 
    377 	/* do not generate any interrupts on buffer operations */
    378 	writereg(PP_BufCFG, 0);
    379 
    380 	/* reset address port, so that autoprobing will keep working */
    381 	outw(PP_ChipID, eth_nic_base + ADD_PORT);
    382 
    383 	return;
    384 }
    385 
    386 /**************************************************************************
    387 ETH_TRANSMIT - Transmit a frame
    388 ***************************************************************************/
    389 
    390 static void cs89x0_transmit(
    391 	struct nic *nic,
    392 	const char *d,			/* Destination */
    393 	unsigned int t,			/* Type */
    394 	unsigned int s,			/* size */
    395 	const char *p)			/* Packet */
    396 {
    397 	unsigned long tmo;
    398 	int           sr;
    399 
    400 	/* does this size have to be rounded??? please,
    401 	   somebody have a look in the specs */
    402 	if ((sr = ((s + ETH_HLEN + 1)&~1)) < ETH_ZLEN)
    403 		sr = ETH_ZLEN;
    404 
    405 retry:
    406 	/* initiate a transmit sequence */
    407 	outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
    408 	outw(sr, eth_nic_base + TX_LEN_PORT);
    409 
    410 	/* Test to see if the chip has allocated memory for the packet */
    411 	if ((readreg(PP_BusST) & READY_FOR_TX_NOW) == 0) {
    412 		/* Oops... this should not happen! */
    413 		printf("cs: unable to send packet; retrying...\n");
    414 		for (tmo = currticks() + 5*TICKS_PER_SEC; currticks() < tmo; );
    415 		cs89x0_reset(nic);
    416 		goto retry; }
    417 
    418 	/* Write the contents of the packet */
    419 	outsw(eth_nic_base + TX_FRAME_PORT, d, ETH_ALEN/2);
    420 	outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr,
    421 	      ETH_ALEN/2);
    422 	outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
    423 	outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
    424 	for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--)
    425 		outw(0, eth_nic_base + TX_FRAME_PORT);
    426 
    427 	/* wait for transfer to succeed */
    428 	for (tmo = currticks()+5*TICKS_PER_SEC;
    429 	     (s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() < tmo;)
    430 		/* nothing */ ;
    431 	if ((s & TX_SEND_OK_BITS) != TX_OK) {
    432 		printf("\ntransmission error %#hX\n", s);
    433 	}
    434 
    435 	return;
    436 }
    437 
    438 /**************************************************************************
    439 ETH_POLL - Wait for a frame
    440 ***************************************************************************/
    441 
    442 static int cs89x0_poll(struct nic *nic, int retrieve)
    443 {
    444 	int status;
    445 
    446 	status = readreg(PP_RxEvent);
    447 
    448 	if ((status & RX_OK) == 0)
    449 		return(0);
    450 
    451 	if ( ! retrieve ) return 1;
    452 
    453 	status = inw(eth_nic_base + RX_FRAME_PORT);
    454 	nic->packetlen = inw(eth_nic_base + RX_FRAME_PORT);
    455 	insw(eth_nic_base + RX_FRAME_PORT, nic->packet, nic->packetlen >> 1);
    456 	if (nic->packetlen & 1)
    457 		nic->packet[nic->packetlen-1] = inw(eth_nic_base + RX_FRAME_PORT);
    458 	return 1;
    459 }
    460 
    461 static void cs89x0_irq(struct nic *nic __unused, irq_action_t action __unused)
    462 {
    463   switch ( action ) {
    464   case DISABLE :
    465     break;
    466   case ENABLE :
    467     break;
    468   case FORCE :
    469     break;
    470   }
    471 }
    472 
    473 static struct nic_operations cs89x0_operations = {
    474 	.connect	= dummy_connect,
    475 	.poll		= cs89x0_poll,
    476 	.transmit	= cs89x0_transmit,
    477 	.irq		= cs89x0_irq,
    478 };
    479 
    480 /**************************************************************************
    481 ETH_PROBE - Look for an adapter
    482 ***************************************************************************/
    483 
    484 static int cs89x0_probe_addr ( isa_probe_addr_t ioaddr ) {
    485 	/* if they give us an odd I/O address, then do ONE write to
    486 	   the address port, to get it back to address zero, where we
    487 	   expect to find the EISA signature word. */
    488 	if (ioaddr & 1) {
    489 		ioaddr &= ~1;
    490 		if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
    491 			return 0;
    492 		outw(PP_ChipID, ioaddr + ADD_PORT);
    493 	}
    494 
    495 	if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
    496 		return 0;
    497 
    498 	return 1;
    499 }
    500 
    501 static int cs89x0_probe ( struct nic *nic, struct isa_device *isa __unused ) {
    502 	int      i, result = -1;
    503 	unsigned rev_type = 0, isa_cnf, cs_revision;
    504 	unsigned short eeprom_buff[CHKSUM_LEN];
    505 
    506 	nic->ioaddr &= ~1; /* LSB = 1 indicates a more aggressive probe */
    507 	eth_nic_base = nic->ioaddr;
    508 
    509 	/* get the chip type */
    510 	rev_type = readreg(PRODUCT_ID_ADD);
    511 	eth_cs_type = rev_type &~ REVISON_BITS;
    512 	cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
    513 
    514 	printf("\ncs: cs89%c0%s rev %c, base %#hX",
    515 	       eth_cs_type==CS8900?'0':'2',
    516 	       eth_cs_type==CS8920M?"M":"",
    517 	       cs_revision,
    518 	       eth_nic_base);
    519 #ifndef EMBEDDED
    520 	/* First check to see if an EEPROM is attached*/
    521 	if ((readreg(PP_SelfST) & EEPROM_PRESENT) == 0) {
    522 		printf("\ncs: no EEPROM...\n");
    523 		outw(PP_ChipID, eth_nic_base + ADD_PORT);
    524 		return 0;
    525 	} else if (get_eeprom_data(START_EEPROM_DATA,CHKSUM_LEN,
    526 				   eeprom_buff) < 0) {
    527 		printf("\ncs: EEPROM read failed...\n");
    528 		outw(PP_ChipID, eth_nic_base + ADD_PORT);
    529 		return 0;
    530 	} else if (get_eeprom_chksum(START_EEPROM_DATA,CHKSUM_LEN,
    531 				     eeprom_buff) < 0) {
    532 		printf("\ncs: EEPROM checksum bad...\n");
    533 		outw(PP_ChipID, eth_nic_base + ADD_PORT);
    534 		return 0;
    535 	}
    536 
    537 	/* get transmission control word but keep the
    538 	   autonegotiation bits */
    539 	eth_auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
    540 	/* Store adapter configuration */
    541 	eth_adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
    542 	/* Store ISA configuration */
    543 	isa_cnf = eeprom_buff[ISA_CNF_OFFSET/2];
    544 
    545 	/* store the initial memory base address */
    546 	eth_mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
    547 
    548 	printf("%s%s%s, addr ",
    549 	       (eth_adapter_cnf & A_CNF_10B_T)?", RJ-45":"",
    550 	       (eth_adapter_cnf & A_CNF_AUI)?", AUI":"",
    551 	       (eth_adapter_cnf & A_CNF_10B_2)?", BNC":"");
    552 
    553 	/* If this is a CS8900 then no pnp soft */
    554 	if (eth_cs_type != CS8900 &&
    555 	    /* Check if the ISA IRQ has been set  */
    556 	    (i = readreg(PP_CS8920_ISAINT) & 0xff,
    557 	     (i != 0 && i < CS8920_NO_INTS)))
    558 		eth_irqno = i;
    559 	else {
    560 		i = isa_cnf & INT_NO_MASK;
    561 		if (eth_cs_type == CS8900) {
    562 			/* the table that follows is dependent
    563 			   upon how you wired up your cs8900
    564 			   in your system.  The table is the
    565 			   same as the cs8900 engineering demo
    566 			   board.  irq_map also depends on the
    567 			   contents of the table.  Also see
    568 			   write_irq, which is the reverse
    569 			   mapping of the table below. */
    570 			if (i < 4) i = "\012\013\014\005"[i];
    571 			else printf("\ncs: BUG: isa_config is %d\n", i); }
    572 		eth_irqno = i; }
    573 
    574         nic->irqno = eth_irqno;
    575 
    576 	/* Retrieve and print the ethernet address. */
    577 	for (i=0; i<ETH_ALEN; i++) {
    578 		nic->node_addr[i] = ((unsigned char *)eeprom_buff)[i];
    579 	}
    580 
    581 	DBG ( "%s\n", eth_ntoa ( nic->node_addr ) );
    582 
    583 #endif
    584 #ifdef EMBEDDED
    585 	/* Retrieve and print the ethernet address. */
    586 	{
    587 		unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
    588 		memcpy(nic->node_addr, MAC_HW_ADDR, 6);
    589 	}
    590 
    591 	DBG ( "%s\n", eth_ntoa ( nic->node_addr ) );
    592 
    593 	eth_adapter_cnf = A_CNF_10B_T | A_CNF_MEDIA_10B_T;
    594 	eth_auto_neg_cnf = EE_AUTO_NEG_ENABLE | IMM_BIT;
    595 #endif
    596 #ifndef EMBEDDED
    597 	/* Set the LineCTL quintuplet based on adapter
    598 	   configuration read from EEPROM */
    599 	if ((eth_adapter_cnf & A_CNF_EXTND_10B_2) &&
    600 	    (eth_adapter_cnf & A_CNF_LOW_RX_SQUELCH))
    601 		eth_linectl = LOW_RX_SQUELCH;
    602 	else
    603 		eth_linectl = 0;
    604 
    605 	/* check to make sure that they have the "right"
    606 	   hardware available */
    607 	switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
    608 	case A_CNF_MEDIA_10B_T: result = eth_adapter_cnf & A_CNF_10B_T;
    609 		break;
    610 	case A_CNF_MEDIA_AUI:   result = eth_adapter_cnf & A_CNF_AUI;
    611 		break;
    612 	case A_CNF_MEDIA_10B_2: result = eth_adapter_cnf & A_CNF_10B_2;
    613 		break;
    614 	default: result = eth_adapter_cnf & (A_CNF_10B_T | A_CNF_AUI |
    615 					     A_CNF_10B_2);
    616 	}
    617 	if (!result) {
    618 		printf("cs: EEPROM is configured for unavailable media\n");
    619 	error:
    620 		writereg(PP_LineCTL, readreg(PP_LineCTL) &
    621 			 ~(SERIAL_TX_ON | SERIAL_RX_ON));
    622 		outw(PP_ChipID, eth_nic_base + ADD_PORT);
    623 		return 0;
    624 	}
    625 #endif
    626 	/* Initialize the card for probing of the attached media */
    627 	cs89x0_reset(nic);
    628 
    629 	/* set the hardware to the configured choice */
    630 	switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
    631 	case A_CNF_MEDIA_10B_T:
    632 		result = detect_tp();
    633 		if (!result) {
    634 			clrline();
    635 			printf("10Base-T (RJ-45%s",
    636 			       ") has no cable\n"); }
    637 		/* check "ignore missing media" bit */
    638 		if (eth_auto_neg_cnf & IMM_BIT)
    639 			/* Yes! I don't care if I see a link pulse */
    640 			result = A_CNF_MEDIA_10B_T;
    641 		break;
    642 	case A_CNF_MEDIA_AUI:
    643 		result = detect_aui(nic);
    644 		if (!result) {
    645 			clrline();
    646 			printf("10Base-5 (AUI%s",
    647 			       ") has no cable\n"); }
    648 		/* check "ignore missing media" bit */
    649 		if (eth_auto_neg_cnf & IMM_BIT)
    650 			/* Yes! I don't care if I see a carrrier */
    651 			result = A_CNF_MEDIA_AUI;
    652 		break;
    653 	case A_CNF_MEDIA_10B_2:
    654 		result = detect_bnc(nic);
    655 		if (!result) {
    656 			clrline();
    657 			printf("10Base-2 (BNC%s",
    658 			       ") has no cable\n"); }
    659 		/* check "ignore missing media" bit */
    660 		if (eth_auto_neg_cnf & IMM_BIT)
    661 			/* Yes! I don't care if I can xmit a packet */
    662 			result = A_CNF_MEDIA_10B_2;
    663 		break;
    664 	case A_CNF_MEDIA_AUTO:
    665 		writereg(PP_LineCTL, eth_linectl | AUTO_AUI_10BASET);
    666 		if (eth_adapter_cnf & A_CNF_10B_T)
    667 			if ((result = detect_tp()) != 0)
    668 				break;
    669 		if (eth_adapter_cnf & A_CNF_AUI)
    670 			if ((result = detect_aui(nic)) != 0)
    671 				break;
    672 		if (eth_adapter_cnf & A_CNF_10B_2)
    673 			if ((result = detect_bnc(nic)) != 0)
    674 				break;
    675 		clrline(); printf("no media detected\n");
    676 		goto error;
    677 	}
    678 	clrline();
    679 	switch(result) {
    680 	case 0:                 printf("no network cable attached to configured media\n");
    681 		goto error;
    682 	case A_CNF_MEDIA_10B_T: printf("using 10Base-T (RJ-45)\n");
    683 		break;
    684 	case A_CNF_MEDIA_AUI:   printf("using 10Base-5 (AUI)\n");
    685 		break;
    686 	case A_CNF_MEDIA_10B_2: printf("using 10Base-2 (BNC)\n");
    687 		break;
    688 	}
    689 
    690 	/* Turn on both receive and transmit operations */
    691 	writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON |
    692 		 SERIAL_TX_ON);
    693 
    694 	return 0;
    695 #ifdef EMBEDDED
    696  error:
    697 	writereg(PP_LineCTL, readreg(PP_LineCTL) &
    698 		 ~(SERIAL_TX_ON | SERIAL_RX_ON));
    699 	outw(PP_ChipID, eth_nic_base + ADD_PORT);
    700 	return 0;
    701 #endif
    702 
    703 	nic->nic_op   = &cs89x0_operations;
    704 	return 1;
    705 }
    706 
    707 static void cs89x0_disable ( struct nic *nic,
    708 			     struct isa_device *isa __unused ) {
    709 	cs89x0_reset(nic);
    710 }
    711 
    712 static isa_probe_addr_t cs89x0_probe_addrs[] = {
    713 #ifndef EMBEDDED
    714 	/* use "conservative" default values for autoprobing */
    715 	0x300, 0x320, 0x340, 0x200, 0x220, 0x240,
    716 	0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
    717 	/* if that did not work, then be more aggressive */
    718 	0x301, 0x321, 0x341, 0x201, 0x221, 0x241,
    719 	0x261, 0x281, 0x2a1, 0x2c1, 0x2e1,
    720 #else
    721 	0x01000300,
    722 #endif
    723 };
    724 
    725 ISA_DRIVER ( cs89x0_driver, cs89x0_probe_addrs, cs89x0_probe_addr,
    726 	     ISAPNP_VENDOR('C','S','C'), 0x0007 );
    727 
    728 DRIVER ( "cs89x0", nic_driver, isa_driver, cs89x0_driver,
    729 	 cs89x0_probe, cs89x0_disable );
    730 
    731 ISA_ROM ( "cs89x0", "Crystal Semiconductor CS89x0" );
    732 
    733 /*
    734  * Local variables:
    735  *  c-basic-offset: 8
    736  *  c-indent-level: 8
    737  *  tab-width: 8
    738  * End:
    739  */
    740