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