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