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