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