FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/if_cs.c
1 /*
2 * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29 /*
30 * $FreeBSD: src/sys/i386/isa/if_cs.c,v 1.1.2.6 1999/09/05 08:12:42 peter Exp $
31 *
32 * Device driver for Crystal Semiconductor CS8920 based ethernet
33 * adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997
34 */
35
36 /* #define CS_DEBUG */
37 #include "cs.h"
38 #include "bpfilter.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/conf.h>
43 #include <sys/errno.h>
44 #include <sys/ioctl.h>
45 #include <sys/kernel.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48 #include <sys/sysctl.h>
49 #include <sys/syslog.h>
50
51 #include <net/if.h>
52 #include <net/if_dl.h>
53 #include <net/if_mib.h>
54 #include <net/if_media.h>
55 #include <net/if_types.h>
56
57 #ifdef INET
58 #include <netinet/in.h>
59 #include <netinet/in_systm.h>
60 #include <netinet/in_var.h>
61 #include <netinet/ip.h>
62 #include <netinet/if_ether.h>
63 #endif
64
65 #ifdef IPX
66 #include <netipx/ipx.h>
67 #include <netipx/ipx_if.h>
68 #endif
69
70 #ifdef NS
71 #include <netns/ns.h>
72 #include <netns/ns_if.h>
73 #endif
74
75 #if NBPFILTER > 0
76 #include <net/bpf.h>
77 #include <net/bpfdesc.h>
78 #endif
79
80 #include <machine/clock.h>
81 #include <machine/md_var.h>
82
83 #include <i386/isa/isa_device.h>
84 #include <i386/isa/icu.h>
85 #include <i386/isa/if_csreg.h>
86
87 #include "pnp.h"
88
89 #if NPNP > 0
90 #include <i386/isa/pnp.h>
91 #endif
92
93 #ifdef CS_USE_64K_DMA
94 #define CS_DMA_BUFFER_SIZE 65536
95 #else
96 #define CS_DMA_BUFFER_SIZE 16384
97 #endif
98
99 /*
100 * cs_softc: per line info and status
101 */
102 static struct cs_softc {
103
104 /* Ethernet common code */
105 struct arpcom arpcom;
106
107 /* Configuration words from EEPROM */
108 int auto_neg_cnf; /* AutoNegotitation configuration */
109 int adapter_cnf; /* Adapter configuration */
110 int isa_config; /* ISA configuration */
111 int chip_type; /* Type of chip */
112
113 struct ifmedia media; /* Media information */
114
115 int nic_addr; /* Base IO address of card */
116 int send_cmd;
117 int line_ctl; /* */
118 int send_underrun;
119 void *recv_ring;
120
121 unsigned char *buffer;
122 int buf_len;
123
124 } cs_softc[NCS];
125
126 static u_long cs_unit = NCS;
127
128 static int cs_recv_delay = 570;
129 SYSCTL_INT(_machdep, OID_AUTO, cs_recv_delay, CTLFLAG_RW, &cs_recv_delay, 0, "");
130
131 static int cs_attach __P((struct cs_softc *, int, int));
132 static int cs_attach_isa __P((struct isa_device *));
133 static void cs_init __P((void *));
134 static int cs_ioctl __P((struct ifnet *, int, caddr_t));
135 static int cs_probe __P((struct isa_device *));
136 static int cs_cs89x0_probe __P((struct cs_softc *,
137 u_short *, short *, int, int, int));
138 static void cs_start __P((struct ifnet *));
139 static void cs_stop __P((struct cs_softc *));
140 static void cs_reset __P((struct cs_softc *));
141 static void cs_watchdog __P((struct ifnet *));
142
143 static int cs_mediachange __P((struct ifnet *));
144 static void cs_mediastatus __P((struct ifnet *, struct ifmediareq *));
145 static int cs_mediaset __P((struct cs_softc *, int));
146
147 static void cs_write_mbufs(struct cs_softc*, struct mbuf*);
148 static void cs_xmit_buf(struct cs_softc*);
149 static int cs_get_packet(struct cs_softc*);
150 static void cs_setmode(struct cs_softc*);
151
152 static int get_eeprom_data(struct cs_softc *sc, int, int, int *);
153 static int get_eeprom_cksum(int, int, int *);
154 static int wait_eeprom_ready( struct cs_softc *);
155 static void control_dc_dc( struct cs_softc *, int );
156 static int send_test_pkt( struct cs_softc * );
157 static int enable_tp(struct cs_softc *);
158 static int enable_aui(struct cs_softc *);
159 static int enable_bnc(struct cs_softc *);
160 static int cs_duplex_auto(struct cs_softc *);
161
162 struct isa_driver csdriver = {
163 cs_probe,
164 cs_attach_isa,
165 CS_NAME,
166 0
167 };
168
169 static int
170 get_eeprom_data( struct cs_softc *sc, int off, int len, int *buffer)
171 {
172 int i;
173
174 #ifdef CS_DEBUG
175 printf(CS_NAME":EEPROM data from %x for %x:\n", off,len);
176 #endif
177
178 for (i=0;i<len;i++) {
179 if (wait_eeprom_ready(sc) < 0) return -1;
180 /* Send command to EEPROM to read */
181 cs_writereg(sc->nic_addr, PP_EECMD, (off+i)|EEPROM_READ_CMD );
182 if (wait_eeprom_ready(sc)<0)
183 return -1;
184 buffer[i] = cs_readreg (sc->nic_addr, PP_EEData);
185
186 #ifdef CS_DEBUG
187 printf("%02x %02x ",(unsigned char)buffer[i],
188 (unsigned char)buffer[i+1]);
189 #endif
190 }
191
192 #ifdef CS_DEBUG
193 printf("\n");
194 #endif
195
196 return 0;
197 }
198
199 static int
200 get_eeprom_cksum(int off, int len, int *buffer)
201 {
202 int i,cksum=0;
203
204 for (i=0;i<len;i++)
205 cksum+=buffer[i];
206 cksum &= 0xffff;
207 if (cksum==0)
208 return 0;
209 return -1;
210 }
211
212 static int
213 wait_eeprom_ready(struct cs_softc *sc)
214 {
215 int timeout=1000;
216 DELAY ( 30000 ); /* XXX should we do some checks here ? */
217 return 0;
218 }
219
220 static void
221 control_dc_dc(struct cs_softc *sc, int on_not_off)
222 {
223 unsigned int self_control = HCB1_ENBL;
224
225 if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0) ^ on_not_off)
226 self_control |= HCB1;
227 else
228 self_control &= ~HCB1;
229 cs_writereg( sc->nic_addr, PP_SelfCTL, self_control );
230
231 DELAY( 500000 );
232 }
233
234
235 static int
236 cs_duplex_auto(struct cs_softc *sc)
237 {
238 int i, error=0, unit=sc->arpcom.ac_if.if_unit;
239
240 cs_writereg(sc->nic_addr, PP_AutoNegCTL,
241 RE_NEG_NOW | ALLOW_FDX | AUTO_NEG_ENABLE );
242 for (i=0; cs_readreg(sc->nic_addr,PP_AutoNegST)&AUTO_NEG_BUSY; i++) {
243 if (i > 40000) {
244 printf(CS_NAME"%1d: full/half duplex "
245 "auto negotiation timeout\n", unit);
246 error = ETIMEDOUT;
247 break;
248 }
249 DELAY(1000);
250 }
251 DELAY( 1000000 );
252 return error;
253 }
254
255 static int
256 enable_tp(struct cs_softc *sc)
257 {
258 int i;
259 int unit = sc->arpcom.ac_if.if_unit;
260
261 cs_writereg(sc->nic_addr, PP_LineCTL, sc->line_ctl & ~AUI_ONLY);
262 control_dc_dc(sc, 0);
263 DELAY( 150000 );
264
265 if ((cs_readreg(sc->nic_addr, PP_LineST) & LINK_OK)==0) {
266 printf(CS_NAME"%1d: failed to enable TP\n", unit);
267 return EINVAL;
268 }
269
270 return 0;
271 }
272
273 /*
274 * XXX This was rewritten from Linux driver without any tests.
275 */
276 static int
277 send_test_pkt(struct cs_softc *sc)
278 {
279 int unit = sc->arpcom.ac_if.if_unit;
280 char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
281 0, 46, /* A 46 in network order */
282 0, 0, /* DSAP=0 & SSAP=0 fields */
283 0xf3, 0 /* Control (Test Req + P bit set) */ };
284 int i;
285 u_char ether_address_backup[ETHER_ADDR_LEN];
286
287 for (i = 0; i < ETHER_ADDR_LEN; i++) {
288 ether_address_backup[i] = sc->arpcom.ac_enaddr[i];
289 }
290
291 cs_writereg(sc->nic_addr, PP_LineCTL,
292 cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_TX_ON );
293 bcopy(test_packet,
294 sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
295 bcopy(test_packet+ETHER_ADDR_LEN,
296 sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
297 outw(sc->nic_addr + TX_CMD_PORT, sc->send_cmd);
298 outw(sc->nic_addr + TX_LEN_PORT, sizeof(test_packet));
299
300 /* Wait for chip to allocate memory */
301 DELAY(50000);
302 if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) {
303 for (i = 0; i < ETHER_ADDR_LEN; i++) {
304 sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
305 }
306 return 0;
307 }
308
309 outsw(sc->nic_addr + TX_FRAME_PORT, test_packet, sizeof(test_packet));
310
311 DELAY(30000);
312
313 if ((cs_readreg(sc->nic_addr,PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
314 for (i = 0; i < ETHER_ADDR_LEN; i++) {
315 sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
316 }
317 return 1;
318 }
319 for (i = 0; i < ETHER_ADDR_LEN; i++) {
320 sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
321 }
322 return 0;
323 }
324
325 /*
326 * XXX This was rewritten from Linux driver without any tests.
327 */
328 static int
329 enable_aui(struct cs_softc *sc)
330 {
331 int unit = sc->arpcom.ac_if.if_unit;
332
333 control_dc_dc(sc, 0);
334 cs_writereg(sc->nic_addr, PP_LineCTL,
335 (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY);
336
337 if (!send_test_pkt(sc)) {
338 printf(CS_NAME"%1d failed to enable AUI\n", unit);
339 return EINVAL;
340 }
341 return 0;
342 }
343
344 /*
345 * XXX This was rewritten from Linux driver without any tests.
346 */
347 static int
348 enable_bnc(struct cs_softc *sc)
349 {
350 int unit = sc->arpcom.ac_if.if_unit;
351
352 control_dc_dc(sc, 1);
353 cs_writereg(sc->nic_addr, PP_LineCTL,
354 (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY);
355
356 if (!send_test_pkt(sc)) {
357 printf(CS_NAME"%1d failed to enable BNC\n", unit);
358 return EINVAL;
359 }
360 return 0;
361 }
362
363 static int
364 cs_cs89x0_probe(struct cs_softc *sc, u_short *dev_irq,
365 short *dev_drq, int iobase, int unit, int flags)
366 {
367 unsigned rev_type = 0;
368 int i, irq=0, result;
369 int eeprom_buff[CHKSUM_LEN];
370 int chip_type, pp_isaint, pp_isadma;
371 char chip_revision;
372
373 if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG) {
374 /* Chip not detected. Let's try to reset it */
375 if (bootverbose)
376 printf(CS_NAME"%1d: trying to reset the chip.\n", unit);
377 outw(iobase+ADD_PORT, PP_SelfCTL);
378 i = inw(iobase+DATA_PORT);
379 outw(iobase+ADD_PORT, PP_SelfCTL);
380 outw(iobase+DATA_PORT, i | POWER_ON_RESET);
381 if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG)
382 return 0;
383 }
384
385 outw(iobase+ADD_PORT, PP_ChipID);
386 if (inw(iobase+DATA_PORT) != CHIP_EISA_ID_SIG)
387 return 0;
388
389 rev_type = cs_readreg(iobase, PRODUCT_ID_ADD);
390 chip_type = rev_type & ~REVISON_BITS;
391 chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
392
393 sc->nic_addr = iobase;
394 sc->chip_type = chip_type;
395 if(chip_type==CS8900) {
396 pp_isaint = PP_CS8900_ISAINT;
397 pp_isadma = PP_CS8900_ISADMA;
398 sc->send_cmd = TX_CS8900_AFTER_ALL;
399 } else {
400 pp_isaint = PP_CS8920_ISAINT;
401 pp_isadma = PP_CS8920_ISADMA;
402 sc->send_cmd = TX_CS8920_AFTER_ALL;
403 }
404
405 /*
406 * Clear some fields so that fail of EEPROM will left them clean
407 */
408 sc->auto_neg_cnf = 0;
409 sc->adapter_cnf = 0;
410 sc->isa_config = 0;
411
412 /*
413 * EEPROM
414 */
415 if((cs_readreg(iobase, PP_SelfST) & EEPROM_PRESENT) == 0) {
416 printf(CS_NAME"%1d: No EEPROM, assuming defaults.\n",
417 unit);
418 } else {
419 if (get_eeprom_data(sc,START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) {
420 printf(CS_NAME"%1d: EEPROM read failed, "
421 "assuming defaults..\n", unit);
422 } else {
423 if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) {
424 printf( CS_NAME"%1d: EEPROM cheksum bad, "
425 "assuming defaults..\n", unit );
426 } else {
427 sc->auto_neg_cnf =
428 eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
429 sc->adapter_cnf =
430 eeprom_buff[ADAPTER_CNF_OFFSET/2];
431 sc->isa_config =
432 eeprom_buff[ISA_CNF_OFFSET/2];
433
434 for (i=0; i<ETHER_ADDR_LEN/2; i++) {
435 sc->arpcom.ac_enaddr[i*2]=
436 eeprom_buff[i];
437 sc->arpcom.ac_enaddr[i*2+1]=
438 eeprom_buff[i] >> 8;
439 }
440
441 /*
442 * If no interrupt specified (or "?"),
443 * use what the board tells us.
444 */
445 if (*dev_irq <= 0) {
446 irq = sc->isa_config & INT_NO_MASK;
447 if (chip_type==CS8900) {
448 switch(irq) {
449 case 0: irq=10; break;
450 case 1: irq=11; break;
451 case 2: irq=12; break;
452 case 3: irq=5; break;
453 default: printf(CS_NAME"%1d: invalid irq in EEPROM.\n",unit);
454 }
455 if (irq!=0)
456 *dev_irq=(u_short)(1<<irq);
457 } else {
458 if (irq!=0 && irq<=CS8920_NO_INTS)
459 *dev_irq=(u_short)(1<<irq);
460 }
461 }
462 }
463 }
464 }
465
466 if ((irq=ffs(*dev_irq))) {
467 irq--;
468 if (chip_type == CS8900) {
469 switch(irq) {
470 case 5: irq = 3; break;
471 case 10: irq = 0; break;
472 case 11: irq = 1; break;
473 case 12: irq = 2; break;
474 default: printf(CS_NAME"%1d: invalid irq\n", unit);
475 return 0;
476 }
477 } else {
478 if (irq > CS8920_NO_INTS) {
479 printf(CS_NAME"%1d: invalid irq\n", unit);
480 return 0;
481 }
482 }
483 cs_writereg(iobase, pp_isaint, irq);
484 } else {
485 printf(CS_NAME"%1d: invalid irq\n", unit);
486 return 0;
487 }
488
489 /*
490 * Temporary disabled
491 *
492 if (drq>0)
493 cs_writereg(iobase, pp_isadma, drq);
494 else {
495 printf( CS_NAME"%1d: incorrect drq\n", unit );
496 return 0;
497 }
498 */
499
500 if (bootverbose)
501 printf(CS_NAME"%1d: model CS89%c0%s rev %c\n"
502 CS_NAME"%1d: media%s%s%s\n"
503 CS_NAME"%1d: irq %d drq %d\n",
504 unit,
505 chip_type==CS8900 ? '' : '2',
506 chip_type==CS8920M ? "M" : "",
507 chip_revision,
508 unit,
509 (sc->adapter_cnf & A_CNF_10B_T) ? " TP" : "",
510 (sc->adapter_cnf & A_CNF_AUI) ? " AUI" : "",
511 (sc->adapter_cnf & A_CNF_10B_2) ? " BNC" : "",
512 unit, (int)*dev_irq, (int)*dev_drq);
513
514 if ((sc->adapter_cnf & A_CNF_EXTND_10B_2) &&
515 (sc->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
516 sc->line_ctl = LOW_RX_SQUELCH;
517 else
518 sc->line_ctl = 0;
519
520
521 return PP_ISAIOB;
522 }
523
524 /*
525 * Determine if the device is present
526 *
527 * on entry:
528 * a pointer to an isa_device struct
529 * on exit:
530 * NULL if device not found
531 * or # of i/o addresses used (if found)
532 */
533 static int
534 cs_probe(struct isa_device *dev)
535 {
536 int nports;
537
538 struct cs_softc *sc=&cs_softc[dev->id_unit];
539
540 nports=cs_cs89x0_probe(sc, &(dev->id_irq), &(dev->id_drq),
541 (dev->id_iobase), (dev->id_unit), (dev->id_flags));
542
543 if (nports)
544 return (nports);
545
546 return (0);
547 }
548
549 /*
550 * Install the interface into kernel networking data structures
551 */
552 static int
553 cs_attach(struct cs_softc *sc, int unit, int flags)
554 {
555 int media=0;
556 /* struct cs_softc *sc = &cs_softc[dev->id_unit]; */
557 struct ifnet *ifp = &(sc->arpcom.ac_if);
558
559 if (!ifp->if_name) {
560 ifp->if_softc=sc;
561 ifp->if_unit=unit;
562 ifp->if_name=csdriver.name;
563 ifp->if_output=ether_output;
564 ifp->if_start=cs_start;
565 ifp->if_ioctl=cs_ioctl;
566 ifp->if_watchdog=cs_watchdog;
567 ifp->if_init=cs_init;
568 ifp->if_snd.ifq_maxlen= IFQ_MAXLEN;
569 /*
570 * MIB DATA
571 */
572 /*
573 ifp->if_linkmib=&sc->mibdata;
574 ifp->if_linkmiblen=sizeof sc->mibdata;
575 */
576
577 ifp->if_flags=(IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST );
578
579 /*
580 * this code still in progress (DMA support)
581 *
582
583 sc->recv_ring=malloc(CS_DMA_BUFFER_SIZE<<1, M_DEVBUF, M_NOWAIT);
584 if (sc->recv_ring == NULL) {
585 log(LOG_ERR,CS_NAME
586 "%d: Couldn't allocate memory for NIC\n", unit);
587 return(0);
588 }
589 if ((sc->recv_ring-(sc->recv_ring & 0x1FFFF))
590 < (128*1024-CS_DMA_BUFFER_SIZE))
591 sc->recv_ring+=16*1024;
592
593 */
594
595 sc->buffer=malloc(ETHER_MAX_LEN-ETHER_CRC_LEN,M_DEVBUF,M_NOWAIT);
596 if (sc->buffer == NULL) {
597 printf(CS_NAME"%d: Couldn't allocate memory for NIC\n",
598 unit);
599 return(0);
600 }
601
602 /*
603 * Initialize the media structures.
604 */
605 ifmedia_init(&sc->media, 0, cs_mediachange, cs_mediastatus);
606
607 if (sc->adapter_cnf & A_CNF_10B_T) {
608 ifmedia_add(&sc->media, IFM_ETHER|IFM_10_T, 0, NULL);
609 if (sc->chip_type != CS8900) {
610 ifmedia_add(&sc->media,
611 IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
612 ifmedia_add(&sc->media,
613 IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
614 }
615 }
616
617 if (sc->adapter_cnf & A_CNF_10B_2)
618 ifmedia_add(&sc->media, IFM_ETHER|IFM_10_2, 0, NULL);
619
620 if (sc->adapter_cnf & A_CNF_AUI)
621 ifmedia_add(&sc->media, IFM_ETHER|IFM_10_5, 0, NULL);
622
623 if (sc->adapter_cnf & A_CNF_MEDIA)
624 ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL);
625
626 /* Set default media from EEPROM */
627 switch (sc->adapter_cnf & A_CNF_MEDIA_TYPE) {
628 case A_CNF_MEDIA_AUTO: media = IFM_ETHER|IFM_AUTO; break;
629 case A_CNF_MEDIA_10B_T: media = IFM_ETHER|IFM_10_T; break;
630 case A_CNF_MEDIA_10B_2: media = IFM_ETHER|IFM_10_2; break;
631 case A_CNF_MEDIA_AUI: media = IFM_ETHER|IFM_10_5; break;
632 default: printf(CS_NAME"%d: adapter has no media\n", unit);
633 }
634 ifmedia_set(&sc->media, media);
635 cs_mediaset(sc, media);
636
637 if_attach(ifp);
638 cs_stop( sc );
639 ether_ifattach(ifp);
640 }
641
642 if (bootverbose)
643 printf(CS_NAME"%d: ethernet address %6D\n",
644 ifp->if_unit, sc->arpcom.ac_enaddr, ":");
645
646 #if NBPFILTER > 0
647 bpfattach(ifp, DLT_EN10MB, sizeof (struct ether_header));
648 #endif
649 return 1;
650 }
651
652 static int
653 cs_attach_isa(struct isa_device *dev)
654 {
655 int unit=dev->id_unit;
656 struct cs_softc *sc=&cs_softc[unit];
657 int flags=dev->id_flags;
658
659 return cs_attach(sc, unit, flags);
660 }
661
662 /*
663 * Initialize the board
664 */
665 static void
666 cs_init(void *xsc)
667 {
668 struct cs_softc *sc=(struct cs_softc *)xsc;
669 struct ifnet *ifp = &sc->arpcom.ac_if;
670 int i, s, result, rx_cfg;
671
672 if (ifp->if_addrlist == (struct ifaddr *) 0)
673 return;
674
675 /*
676 * reset whatchdog timer
677 */
678 ifp->if_timer=0;
679 sc->buf_len = 0;
680
681 s=splimp();
682
683 /*
684 * Hardware initialization of cs
685 */
686
687 /* Enable receiver and transmitter */
688 cs_writereg(sc->nic_addr, PP_LineCTL,
689 cs_readreg( sc->nic_addr, PP_LineCTL ) |
690 SERIAL_RX_ON | SERIAL_TX_ON);
691
692 /* Configure the receiver mode */
693 cs_setmode(sc);
694
695 /*
696 * This defines what type of frames will cause interrupts
697 * Bad frames should generate interrupts so that the driver
698 * could track statistics of discarded packets
699 */
700 rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL | RX_RUNT_ENBL |
701 RX_EXTRA_DATA_ENBL;
702 if (sc->isa_config & STREAM_TRANSFER)
703 rx_cfg |= RX_STREAM_ENBL;
704 cs_writereg(sc->nic_addr, PP_RxCFG, rx_cfg);
705
706 cs_writereg(sc->nic_addr, PP_TxCFG, TX_LOST_CRS_ENBL |
707 TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL |
708 TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
709
710 cs_writereg(sc->nic_addr, PP_BufCFG, READY_FOR_TX_ENBL |
711 RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL |
712 TX_UNDERRUN_ENBL /*| RX_DMA_ENBL*/);
713
714 /* Write MAC address into IA filter */
715 for (i=0; i<ETHER_ADDR_LEN/2; i++)
716 cs_writereg(sc->nic_addr, PP_IA+i*2,
717 sc->arpcom.ac_enaddr[i*2] |
718 (sc->arpcom.ac_enaddr[i*2+1] << 8) );
719
720 /*
721 * Now enable everything
722 */
723 /*
724 #ifdef CS_USE_64K_DMA
725 cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K);
726 #else
727
728 cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ);
729 #endif
730 */
731 cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ);
732
733 /*
734 * Set running and clear output active flags
735 */
736 sc->arpcom.ac_if.if_flags |= IFF_RUNNING;
737 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
738
739 /*
740 * Start sending process
741 */
742 cs_start(ifp);
743
744 (void) splx(s);
745 }
746
747 /*
748 * Get the packet from the board and send it to the upper layer
749 * via ether_input().
750 */
751 static int
752 cs_get_packet(struct cs_softc *sc)
753 {
754 struct ifnet *ifp = &(sc->arpcom.ac_if);
755 int iobase = sc->nic_addr, status, length;
756 struct ether_header *eh;
757 struct mbuf *m;
758
759 #ifdef CS_DEBUG
760 int i;
761 #endif
762
763 status = inw(iobase + RX_FRAME_PORT);
764 length = inw(iobase + RX_FRAME_PORT);
765
766 #ifdef CS_DEBUG
767 printf(CS_NAME"%1d: rcvd: stat %x, len %d\n",
768 ifp->if_unit, status, length);
769 #endif
770
771 if (!(status & RX_OK)) {
772 #ifdef CS_DEBUG
773 printf(CS_NAME"%1d: bad pkt stat %x\n", ifp->if_unit, status);
774 #endif
775 ifp->if_ierrors++;
776 return -1;
777 }
778
779 MGETHDR(m, M_DONTWAIT, MT_DATA);
780 if (m==NULL)
781 return -1;
782
783 if (length > MHLEN) {
784 MCLGET(m, M_DONTWAIT);
785 if (!(m->m_flags & M_EXT)) {
786 m_freem(m);
787 return -1;
788 }
789 }
790
791 /* Initialize packet's header info */
792 m->m_pkthdr.rcvif = ifp;
793 m->m_pkthdr.len = length;
794 m->m_len = length;
795
796 /* Get the data */
797 insw(iobase + RX_FRAME_PORT, m->m_data, (length+1)>>1);
798
799 eh = mtod(m, struct ether_header *);
800
801 #if NBPFILTER > 0
802 if (ifp->if_bpf)
803 bpf_mtap(ifp, m);
804 #endif
805
806 #ifdef CS_DEBUG
807 for (i=0;i<length;i++)
808 printf(" %02x",(unsigned char)*((char *)(m->m_data+i)));
809 printf( "\n" );
810 #endif
811
812 if (status & (RX_IA | RX_BROADCAST) ||
813 (ifp->if_flags & IFF_MULTICAST && status & RX_HASHED)) {
814 m->m_pkthdr.len -= sizeof(struct ether_header);
815 m->m_len -= sizeof(struct ether_header);
816 m->m_data += sizeof(struct ether_header);
817
818 /* Feed the packet to the upper layer */
819 ether_input(ifp, eh, m);
820
821 ifp->if_ipackets++;
822
823 if (length==ETHER_MAX_LEN-ETHER_CRC_LEN)
824 DELAY( cs_recv_delay );
825 } else {
826 m_freem(m);
827 }
828
829 return 0;
830 }
831
832 /*
833 * Software calls interrupt handler
834 */
835 static void
836 csintr_sc(struct cs_softc *sc, int unit)
837 {
838 struct ifnet *ifp = &(sc->arpcom.ac_if);
839 int status, s;
840
841 #ifdef CS_DEBUG
842 printf(CS_NAME"%1d: Interrupt.\n", unit);
843 #endif
844
845 while ((status=cs_readword(sc->nic_addr, ISQ_PORT))) {
846
847 #ifdef CS_DEBUG
848 printf( CS_NAME"%1d:from ISQ: %04x\n", unit, status );
849 #endif
850
851 switch (status & ISQ_EVENT_MASK) {
852 case ISQ_RECEIVER_EVENT:
853 cs_get_packet(sc);
854 break;
855
856 case ISQ_TRANSMITTER_EVENT:
857 if (status & TX_OK)
858 ifp->if_opackets++;
859 else
860 ifp->if_oerrors++;
861 ifp->if_flags &= ~IFF_OACTIVE;
862 ifp->if_timer = 0;
863 break;
864
865 case ISQ_BUFFER_EVENT:
866 if (status & READY_FOR_TX) {
867 ifp->if_flags &= ~IFF_OACTIVE;
868 ifp->if_timer = 0;
869 }
870
871 if (status & TX_UNDERRUN) {
872 ifp->if_flags &= ~IFF_OACTIVE;
873 ifp->if_timer = 0;
874 ifp->if_oerrors++;
875 }
876 break;
877
878 case ISQ_RX_MISS_EVENT:
879 ifp->if_ierrors+=(status>>6);
880 break;
881
882 case ISQ_TX_COL_EVENT:
883 ifp->if_collisions+=(status>>6);
884 break;
885 }
886 }
887
888 if (!(ifp->if_flags & IFF_OACTIVE)) {
889 cs_start(ifp);
890 }
891 }
892
893 /*
894 * Handle interrupts
895 */
896 void
897 csintr(int unit)
898 {
899 struct cs_softc *sc = &cs_softc[unit];
900
901 csintr_sc(sc, unit);
902 }
903
904 /*
905 * Save the data in buffer
906 */
907
908 static void
909 cs_write_mbufs( struct cs_softc *sc, struct mbuf *m )
910 {
911 int len;
912 struct mbuf *mp;
913 unsigned char *data, *buf;
914
915 for (mp=m, buf=sc->buffer, sc->buf_len=0; mp != NULL; mp=mp->m_next) {
916 len = mp->m_len;
917
918 /*
919 * Ignore empty parts
920 */
921 if (!len)
922 continue;
923
924 /*
925 * Find actual data address
926 */
927 data = mtod(mp, caddr_t);
928
929 bcopy((caddr_t) data, (caddr_t) buf, len);
930 buf += len;
931 sc->buf_len += len;
932 }
933 }
934
935
936 static void
937 cs_xmit_buf( struct cs_softc *sc )
938 {
939 outsw(sc->nic_addr+TX_FRAME_PORT, sc->buffer, (sc->buf_len+1)>>1);
940 sc->buf_len = 0;
941 }
942
943 static void
944 cs_start(struct ifnet *ifp)
945 {
946 int s, length;
947 struct mbuf *m, *mp;
948 struct cs_softc *sc = ifp->if_softc;
949
950 s = splimp();
951
952 for (;;) {
953 if (sc->buf_len)
954 length = sc->buf_len;
955 else {
956 IF_DEQUEUE( &ifp->if_snd, m );
957
958 if (m==NULL) {
959 (void) splx(s);
960 return;
961 }
962
963 for (length=0, mp=m; mp != NULL; mp=mp->m_next)
964 length += mp->m_len;
965
966 /* Skip zero-length packets */
967 if (length == 0) {
968 m_freem(m);
969 continue;
970 }
971
972 cs_write_mbufs(sc, m);
973
974 #if NBPFILTER > 0
975 if (ifp->if_bpf) {
976 bpf_mtap(ifp, m);
977 }
978 #endif
979
980 m_freem(m);
981 }
982
983 /*
984 * Issue a SEND command
985 */
986 outw(sc->nic_addr+TX_CMD_PORT, sc->send_cmd);
987 outw(sc->nic_addr+TX_LEN_PORT, length );
988
989 /*
990 * If there's no free space in the buffer then leave
991 * this packet for the next time: indicate output active
992 * and return.
993 */
994 if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) {
995 ifp->if_timer = sc->buf_len;
996 (void) splx(s);
997 ifp->if_flags |= IFF_OACTIVE;
998 return;
999 }
1000
1001 cs_xmit_buf(sc);
1002
1003 /*
1004 * Set the watchdog timer in case we never hear
1005 * from board again. (I don't know about correct
1006 * value for this timeout)
1007 */
1008 ifp->if_timer = length;
1009
1010 (void) splx(s);
1011 ifp->if_flags |= IFF_OACTIVE;
1012 return;
1013 }
1014 }
1015
1016 /*
1017 * Stop everything on the interface
1018 */
1019 static void
1020 cs_stop(struct cs_softc *sc)
1021 {
1022 int s = splimp();
1023
1024 cs_writereg(sc->nic_addr, PP_RxCFG, 0);
1025 cs_writereg(sc->nic_addr, PP_TxCFG, 0);
1026 cs_writereg(sc->nic_addr, PP_BufCFG, 0);
1027 cs_writereg(sc->nic_addr, PP_BusCTL, 0);
1028
1029 sc->arpcom.ac_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1030 sc->arpcom.ac_if.if_timer = 0;
1031
1032 (void) splx(s);
1033 }
1034
1035 /*
1036 * Reset the interface
1037 */
1038 static void
1039 cs_reset(struct cs_softc *sc)
1040 {
1041 cs_stop(sc);
1042 cs_init(sc);
1043 }
1044
1045 static void
1046 cs_setmode(struct cs_softc *sc)
1047 {
1048 struct ifnet *ifp = &(sc->arpcom.ac_if);
1049 int rx_ctl;
1050
1051 /* Stop the receiver while changing filters */
1052 cs_writereg(sc->nic_addr, PP_LineCTL,
1053 cs_readreg(sc->nic_addr, PP_LineCTL) & ~SERIAL_RX_ON);
1054
1055 if (ifp->if_flags & IFF_PROMISC) {
1056 /* Turn on promiscuous mode. */
1057 rx_ctl = RX_OK_ACCEPT | RX_PROM_ACCEPT;
1058 } else {
1059 if (ifp->if_flags & IFF_MULTICAST) {
1060 /* Allow receiving frames with multicast addresses */
1061 rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT |
1062 RX_OK_ACCEPT | RX_MULTCAST_ACCEPT;
1063 /*
1064 * Here the reconfiguration of chip's multicast
1065 * filters should be done but I've no idea about
1066 * hash transformation in this chip. If you can
1067 * add this code or describe me the transformation
1068 * I'd be very glad.
1069 */
1070 } else {
1071 /*
1072 * Receive only good frames addressed for us and
1073 * good broadcasts.
1074 */
1075 rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT |
1076 RX_OK_ACCEPT;
1077 }
1078 }
1079
1080 /* Set up the filter */
1081 cs_writereg(sc->nic_addr, PP_RxCTL, RX_DEF_ACCEPT | rx_ctl);
1082
1083 /* Turn on receiver */
1084 cs_writereg(sc->nic_addr, PP_LineCTL,
1085 cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_RX_ON);
1086 }
1087
1088 static int
1089 cs_ioctl(register struct ifnet *ifp, int command, caddr_t data)
1090 {
1091 struct cs_softc *sc=ifp->if_softc;
1092 struct ifreq *ifr = (struct ifreq *)data;
1093 int s,error=0;
1094
1095 #ifdef CS_DEBUG
1096 printf(CS_NAME"%d: ioctl(%x)\n",sc->arpcom.ac_if.if_unit,command);
1097 #endif
1098
1099 s=splimp();
1100
1101 switch (command) {
1102 case SIOCSIFADDR:
1103 case SIOCGIFADDR:
1104 case SIOCSIFMTU:
1105 ether_ioctl(ifp, command, data);
1106 break;
1107
1108 case SIOCSIFFLAGS:
1109 /*
1110 * Switch interface state between "running" and
1111 * "stopped", reflecting the UP flag.
1112 */
1113 if (sc->arpcom.ac_if.if_flags & IFF_UP) {
1114 if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)==0) {
1115 cs_init(sc);
1116 }
1117 } else {
1118 if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)!=0) {
1119 cs_stop(sc);
1120 }
1121 }
1122 /*
1123 * Promiscuous and/or multicast flags may have changed,
1124 * so reprogram the multicast filter and/or receive mode.
1125 *
1126 * See note about multicasts in cs_setmode
1127 */
1128 cs_setmode(sc);
1129 break;
1130
1131 case SIOCADDMULTI:
1132 case SIOCDELMULTI:
1133 /*
1134 * Update out multicast list.
1135 */
1136 error = (command == SIOCADDMULTI)
1137 ? ether_addmulti(ifr, &sc->arpcom)
1138 : ether_delmulti(ifr, &sc->arpcom);
1139
1140 if (error == ENETRESET) {
1141 /*
1142 * Multicast list has changed; set the hardware filter
1143 * accordingly.
1144 *
1145 * See note about multicasts in cs_setmode
1146 */
1147 cs_setmode(sc);
1148 error = 0;
1149 }
1150 break;
1151
1152 case SIOCSIFMEDIA:
1153 case SIOCGIFMEDIA:
1154 error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
1155 break;
1156
1157 default:
1158 error = EINVAL;
1159 }
1160
1161 (void) splx(s);
1162 return error;
1163 }
1164
1165 /*
1166 * Device timeout/watchdog routine. Entered if the device neglects to
1167 * generate an interrupt after a transmit has been started on it.
1168 */
1169 static void
1170 cs_watchdog(struct ifnet *ifp)
1171 {
1172 struct cs_softc *sc = &cs_softc[ifp->if_unit];
1173
1174 ifp->if_oerrors++;
1175 log(LOG_ERR, CS_NAME"%d: device timeout\n", ifp->if_unit);
1176
1177 /* Reset the interface */
1178 if (ifp->if_flags & IFF_UP)
1179 cs_reset(sc);
1180 else
1181 cs_stop(sc);
1182 }
1183
1184 static int
1185 cs_mediachange(struct ifnet *ifp)
1186 {
1187 struct cs_softc *sc = ifp->if_softc;
1188 struct ifmedia *ifm = &sc->media;
1189
1190 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1191 return EINVAL;
1192
1193 return cs_mediaset(sc, ifm->ifm_media);
1194 }
1195
1196 static void
1197 cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1198 {
1199 int line_status;
1200 struct cs_softc *sc = ifp->if_softc;
1201
1202 ifmr->ifm_active = IFM_ETHER;
1203 line_status = cs_readreg(sc->nic_addr, PP_LineST);
1204 if (line_status & TENBASET_ON) {
1205 ifmr->ifm_active |= IFM_10_T;
1206 if (sc->chip_type != CS8900) {
1207 if (cs_readreg(sc->nic_addr, PP_AutoNegST) & FDX_ACTIVE)
1208 ifmr->ifm_active |= IFM_FDX;
1209 if (cs_readreg(sc->nic_addr, PP_AutoNegST) & HDX_ACTIVE)
1210 ifmr->ifm_active |= IFM_HDX;
1211 }
1212 ifmr->ifm_status = IFM_AVALID;
1213 if (line_status & LINK_OK)
1214 ifmr->ifm_status |= IFM_ACTIVE;
1215 } else {
1216 if (line_status & AUI_ON) {
1217 cs_writereg(sc->nic_addr, PP_SelfCTL,
1218 cs_readreg(sc->nic_addr, PP_SelfCTL) |
1219 HCB1_ENBL);
1220 if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^
1221 (cs_readreg(sc->nic_addr, PP_SelfCTL)&HCB1))
1222 ifmr->ifm_active |= IFM_10_2;
1223 else
1224 ifmr->ifm_active |= IFM_10_5;
1225 }
1226 }
1227 }
1228
1229 static int
1230 cs_mediaset(struct cs_softc *sc, int media)
1231 {
1232 int error;
1233
1234 /* Stop the receiver & transmitter */
1235 cs_writereg(sc->nic_addr, PP_LineCTL,
1236 cs_readreg(sc->nic_addr, PP_LineCTL) &
1237 ~(SERIAL_RX_ON | SERIAL_TX_ON));
1238
1239 #ifdef CS_DEBUG
1240 printf(CS_NAME"%d: cs_setmedia(%x)\n",sc->arpcom.ac_if.if_unit,media);
1241 #endif
1242
1243 switch (IFM_SUBTYPE(media)) {
1244 case IFM_AUTO:
1245 if ((error=enable_tp(sc))==0)
1246 error = cs_duplex_auto(sc);
1247 else if (error=enable_bnc(sc))
1248 error = enable_aui(sc);
1249 break;
1250 case IFM_10_T:
1251 if (error=enable_tp(sc))
1252 break;
1253 if (media & IFM_FDX)
1254 cs_duplex_full(sc);
1255 else if (media & IFM_HDX)
1256 cs_duplex_half(sc);
1257 else
1258 error = cs_duplex_auto(sc);
1259 break;
1260 case IFM_10_2:
1261 error = enable_bnc(sc);
1262 break;
1263 case IFM_10_5:
1264 error = enable_aui(sc);
1265 break;
1266 }
1267
1268 /*
1269 * Turn the transmitter & receiver back on
1270 */
1271 cs_writereg(sc->nic_addr, PP_LineCTL,
1272 cs_readreg( sc->nic_addr, PP_LineCTL ) |
1273 SERIAL_RX_ON | SERIAL_TX_ON);
1274
1275 return error;
1276 }
1277
1278
1279 #if NPNP > 0
1280
1281 static struct cspnp_ids {
1282 u_long vend_id;
1283 char *id_str;
1284 } cspnp_ids[]= {
1285 { 0x4060630e, "CSC6040" },
1286 { 0x10104d24, "IBM EtherJet" },
1287 { 0 }
1288 };
1289
1290 static char *cs_pnp_probe(u_long, u_long);
1291 static void cs_pnp_attach(u_long, u_long, char *, struct isa_device *);
1292
1293 struct pnp_device cs_pnp = {
1294 "CS8920 based PnP Ethernet",
1295 cs_pnp_probe,
1296 cs_pnp_attach,
1297 &cs_unit,
1298 &net_imask /* imask */
1299 };
1300
1301 DATA_SET (pnpdevice_set, cs_pnp);
1302
1303 struct csintr_list {
1304 struct cs_softc *sc;
1305 int unit;
1306 struct csintr_list *next;
1307 };
1308
1309 static struct csintr_list *csintr_head;
1310
1311 static void csintr_pnp_add(struct cs_softc *sc, int unit);
1312 static void csintr_pnp(int unit);
1313
1314 static void
1315 csintr_pnp_add(struct cs_softc *sc, int unit)
1316 {
1317 struct csintr_list *intr;
1318
1319 if (!sc) return;
1320
1321 intr = malloc (sizeof (*intr), M_DEVBUF, M_WAITOK);
1322 if (!intr) return;
1323
1324 intr->sc = sc;
1325 intr->unit = unit;
1326 intr->next = csintr_head;
1327 csintr_head = intr;
1328 }
1329
1330 /*
1331 * Interrupt handler for PNP installed card
1332 * We have to find the number of the card.
1333 */
1334 static void
1335 csintr_pnp(int unit)
1336 {
1337 struct cs_softc *sc;
1338 struct csintr_list *intr;
1339
1340 for (intr=csintr_head; intr; intr=intr->next) {
1341 if (intr->unit == unit)
1342 csintr_sc(intr->sc, unit);
1343 break;
1344 }
1345 }
1346
1347 static char *
1348 cs_pnp_probe(u_long csn, u_long vend_id)
1349 {
1350 struct cspnp_ids *ids;
1351 char *s=NULL;
1352
1353 for(ids = cspnp_ids; ids->vend_id != 0; ids++) {
1354 if (vend_id == ids->vend_id) {
1355 s = ids->id_str;
1356 break;
1357 }
1358 }
1359
1360 if (s) {
1361 struct pnp_cinfo d;
1362 int ldn = 0;
1363
1364 read_pnp_parms(&d, ldn);
1365 if (d.enable == 0) {
1366 printf("This is a %s, but LDN %d is disabled\n", s, ldn);
1367 return NULL ;
1368 }
1369 return s;
1370 }
1371
1372 return NULL ;
1373 }
1374
1375 static void
1376 cs_pnp_attach(u_long csn, u_long vend_id, char *name,
1377 struct isa_device *dev)
1378 {
1379
1380 struct pnp_cinfo d;
1381 int ldn = 0;
1382 int iobase, unit, flags;
1383 u_short irq;
1384 short drq;
1385 struct isa_device *dvp;
1386 struct cs_softc *sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
1387
1388 if (read_pnp_parms ( &d , ldn ) == 0 ) {
1389 printf("failed to read pnp parms\n");
1390 return;
1391 }
1392
1393 write_pnp_parms( &d, ldn );
1394 enable_pnp_card();
1395
1396 iobase = dev->id_iobase = d.port[0];
1397 irq = dev->id_irq = (1 << d.irq[0] );
1398 drq = dev->id_drq = d.drq[0];
1399 dev->id_maddr = 0;
1400 dev->id_intr = csintr_pnp;
1401 flags = dev->id_flags = 0;
1402 unit = dev->id_unit;
1403
1404 if (dev->id_driver == NULL) {
1405 dev->id_driver = &csdriver;
1406 dvp = find_isadev(isa_devtab_net, &csdriver, 0);
1407 if (dvp != NULL)
1408 dev->id_id = dvp->id_id;
1409 }
1410
1411 if (!sc) return;
1412
1413 bzero(sc, sizeof *sc);
1414 if (cs_cs89x0_probe(sc, &irq, &drq, iobase, unit, flags) == 0
1415 || cs_attach(sc, unit, flags) == 0) {
1416 free(sc, M_DEVBUF);
1417 } else {
1418 if ((irq != dev->id_irq)
1419 || (drq != dev->id_drq)
1420 || (iobase != dev->id_iobase)
1421 || (unit != dev->id_unit)
1422 || (flags != dev->id_flags)
1423 ) {
1424 printf("failed to pnp card parametars\n");
1425 }
1426 }
1427 csintr_pnp_add(sc, dev->id_unit);
1428 }
1429 #endif /* NPNP */
Cache object: 54f6385a863bd0cc2955ffc26d6a6172
|