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