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
23FILE_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 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@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 <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
98static unsigned short	eth_nic_base;
99static unsigned long    eth_mem_start;
100static unsigned short   eth_irqno;
101static unsigned short   eth_cs_type;	/* one of: CS8900, CS8920, CS8920M  */
102static unsigned short   eth_auto_neg_cnf;
103static unsigned short   eth_adapter_cnf;
104static unsigned short	eth_linectl;
105
106/*************************************************************************
107	CS89x0 - specific routines
108**************************************************************************/
109
110static inline int readreg(int portno)
111{
112	outw(portno, eth_nic_base + ADD_PORT);
113	return inw(eth_nic_base + DATA_PORT);
114}
115
116static 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/*************************************************************************
124EEPROM access
125**************************************************************************/
126
127static 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
140static 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
169static 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/*************************************************************************
183Activate all of the available media and probe for network
184**************************************************************************/
185
186static void clrline(void)
187{
188	int i;
189
190	putchar('\r');
191	for (i = 79; i--; ) putchar(' ');
192	printf("\rcs: ");
193	return;
194}
195
196static 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
215static 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 */
262static 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
301static 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
314static 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/**************************************************************************
328ETH_RESET - Reset adapter
329***************************************************************************/
330
331static 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/**************************************************************************
387ETH_TRANSMIT - Transmit a frame
388***************************************************************************/
389
390static 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
405retry:
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/**************************************************************************
439ETH_POLL - Wait for a frame
440***************************************************************************/
441
442static 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
461static 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
473static struct nic_operations cs89x0_operations = {
474	.connect	= dummy_connect,
475	.poll		= cs89x0_poll,
476	.transmit	= cs89x0_transmit,
477	.irq		= cs89x0_irq,
478};
479
480/**************************************************************************
481ETH_PROBE - Look for an adapter
482***************************************************************************/
483
484static 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
501static 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
707static void cs89x0_disable ( struct nic *nic,
708			     struct isa_device *isa __unused ) {
709	cs89x0_reset(nic);
710}
711
712static 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
725ISA_DRIVER ( cs89x0_driver, cs89x0_probe_addrs, cs89x0_probe_addr,
726	     ISAPNP_VENDOR('C','S','C'), 0x0007 );
727
728DRIVER ( "cs89x0", nic_driver, isa_driver, cs89x0_driver,
729	 cs89x0_probe, cs89x0_disable );
730
731ISA_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