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