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