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