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