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