Eliminate use of curthread in if_ioctl functions by passing down the
[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  */
28
29 /*
30  * $FreeBSD: src/sys/dev/cs/if_cs.c,v 1.19.2.1 2001/01/25 20:13:48 imp Exp $
31  * $DragonFly: src/sys/dev/netif/cs/if_cs.c,v 1.7 2004/03/23 22:18:59 hsu Exp $
32  *
33  * Device driver for Crystal Semiconductor CS8920 based ethernet
34  *   adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997
35  */
36
37 /*
38 #define  CS_DEBUG 
39  */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
47 #include <sys/kernel.h>
48 #include <sys/sysctl.h>
49 #include <sys/syslog.h>
50
51 #include <sys/module.h>
52 #include <sys/bus.h>
53 #include <machine/bus.h>
54 #include <sys/rman.h>
55 #include <machine/resource.h>
56 #include <machine/clock.h>
57
58 #include <net/if.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(dev, SYS_RES_IRQ, &rid,
545                                  0ul, ~0ul, 1, (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_output=ether_output;
594         ifp->if_start=cs_start;
595         ifp->if_ioctl=cs_ioctl;
596         ifp->if_watchdog=cs_watchdog;
597         ifp->if_init=cs_init;
598         ifp->if_snd.ifq_maxlen= IFQ_MAXLEN;
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_NOWAIT);
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_NOWAIT);
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
672         if (bootverbose)
673                 printf("%s: ethernet address %6D\n",
674                        ifp->if_xname, sc->arpcom.ac_enaddr, ":");
675
676         return (0);
677 }
678
679 /*
680  * Initialize the board
681  */
682 static void
683 cs_init(void *xsc)
684 {
685         struct cs_softc *sc=(struct cs_softc *)xsc;
686         struct ifnet *ifp = &sc->arpcom.ac_if;
687         int i, s, rx_cfg;
688
689         /* address not known */
690         if (TAILQ_EMPTY(&ifp->if_addrhead)) /* unlikely? XXX */
691                 return;
692
693         /*
694          * reset whatchdog timer
695          */
696         ifp->if_timer=0;
697         sc->buf_len = 0;
698         
699         s=splimp();
700
701         /*
702          * Hardware initialization of cs
703          */
704
705         /* Enable receiver and transmitter */
706         cs_writereg(sc->nic_addr, PP_LineCTL,
707                 cs_readreg( sc->nic_addr, PP_LineCTL ) |
708                 SERIAL_RX_ON | SERIAL_TX_ON);
709
710         /* Configure the receiver mode */
711         cs_setmode(sc);
712
713         /*
714          * This defines what type of frames will cause interrupts
715          * Bad frames should generate interrupts so that the driver
716          * could track statistics of discarded packets
717          */
718         rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL | RX_RUNT_ENBL |
719                  RX_EXTRA_DATA_ENBL;
720         if (sc->isa_config & STREAM_TRANSFER)
721                 rx_cfg |= RX_STREAM_ENBL;
722         cs_writereg(sc->nic_addr, PP_RxCFG, rx_cfg);
723
724         cs_writereg(sc->nic_addr, PP_TxCFG, TX_LOST_CRS_ENBL |
725                     TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL |
726                     TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
727
728         cs_writereg(sc->nic_addr, PP_BufCFG, READY_FOR_TX_ENBL |
729                     RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL |
730                     TX_UNDERRUN_ENBL /*| RX_DMA_ENBL*/);
731
732         /* Write MAC address into IA filter */
733         for (i=0; i<ETHER_ADDR_LEN/2; i++)
734                 cs_writereg(sc->nic_addr, PP_IA+i*2,
735                             sc->arpcom.ac_enaddr[i*2] |
736                             (sc->arpcom.ac_enaddr[i*2+1] << 8) );
737
738         /*
739          * Now enable everything
740          */
741 /*
742 #ifdef  CS_USE_64K_DMA
743         cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K);
744         #else
745
746         cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ);
747 #endif
748 */
749         cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ);
750         
751         /*
752          * Set running and clear output active flags
753          */
754         sc->arpcom.ac_if.if_flags |= IFF_RUNNING;
755         sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
756
757         /*
758          * Start sending process
759          */
760         cs_start(ifp);
761
762         (void) splx(s);
763 }
764
765 /*
766  * Get the packet from the board and send it to the upper layer
767  * via ether_input().
768  */
769 static int
770 cs_get_packet(struct cs_softc *sc)
771 {
772         struct ifnet *ifp = &(sc->arpcom.ac_if);
773         int iobase = sc->nic_addr, status, length;
774         struct ether_header *eh;
775         struct mbuf *m;
776
777 #ifdef CS_DEBUG
778         int i;
779 #endif
780
781         status = inw(iobase + RX_FRAME_PORT);
782         length = inw(iobase + RX_FRAME_PORT);
783
784 #ifdef CS_DEBUG
785         printf("%s: rcvd: stat %x, len %d\n",
786                 ifp->if_xname, status, length);
787 #endif
788
789         if (!(status & RX_OK)) {
790 #ifdef CS_DEBUG
791                 printf"%s: bad pkt stat %x\n", ifp->if_xname, status);
792 #endif
793                 ifp->if_ierrors++;
794                 return -1;
795         }
796
797         MGETHDR(m, M_DONTWAIT, MT_DATA);
798         if (m==NULL)
799                 return -1;
800
801         if (length > MHLEN) {
802                 MCLGET(m, M_DONTWAIT);
803                 if (!(m->m_flags & M_EXT)) {
804                         m_freem(m);
805                         return -1;
806                 }
807         }
808
809         /* Initialize packet's header info */
810         m->m_pkthdr.rcvif = ifp;
811         m->m_pkthdr.len = length;
812         m->m_len = length;
813
814         /* Get the data */
815         insw(iobase + RX_FRAME_PORT, m->m_data, (length+1)>>1);
816
817         eh = mtod(m, struct ether_header *);
818
819 #ifdef CS_DEBUG
820         for (i=0;i<length;i++)
821              printf(" %02x",(unsigned char)*((char *)(m->m_data+i)));
822         printf( "\n" );
823 #endif
824
825         if (status & (RX_IA | RX_BROADCAST) || 
826             (ifp->if_flags & IFF_MULTICAST && status & RX_HASHED)) {
827                 m->m_pkthdr.len -= sizeof(struct ether_header);
828                 m->m_len -= sizeof(struct ether_header);
829                 m->m_data += sizeof(struct ether_header);
830
831                 /* Feed the packet to the upper layer */
832                 ether_input(ifp, eh, m);
833
834                 ifp->if_ipackets++;
835
836                 if (length==ETHER_MAX_LEN-ETHER_CRC_LEN)
837                         DELAY( cs_recv_delay );
838         } else {
839                 m_freem(m);
840         }
841
842         return 0;
843 }
844
845 /*
846  * Handle interrupts
847  */
848 void
849 csintr(void *arg)
850 {
851         struct cs_softc *sc = (struct cs_softc*) arg;
852         struct ifnet *ifp = &(sc->arpcom.ac_if);
853         int status;
854
855 #ifdef CS_DEBUG
856         printf("%s: Interrupt.\n", ifp->xname);
857 #endif
858
859         while ((status=cs_readword(sc->nic_addr, ISQ_PORT))) {
860
861 #ifdef CS_DEBUG
862                 printf("%s:from ISQ: %04x\n", ifp->if_xname, status );
863 #endif
864
865                 switch (status & ISQ_EVENT_MASK) {
866                 case ISQ_RECEIVER_EVENT:
867                         cs_get_packet(sc);
868                         break;
869
870                 case ISQ_TRANSMITTER_EVENT:
871                         if (status & TX_OK)
872                                 ifp->if_opackets++;
873                         else
874                                 ifp->if_oerrors++;
875                         ifp->if_flags &= ~IFF_OACTIVE;
876                         ifp->if_timer = 0;
877                         break;
878
879                 case ISQ_BUFFER_EVENT:
880                         if (status & READY_FOR_TX) {
881                                 ifp->if_flags &= ~IFF_OACTIVE;
882                                 ifp->if_timer = 0;
883                         }
884
885                         if (status & TX_UNDERRUN) {
886                                 ifp->if_flags &= ~IFF_OACTIVE;
887                                 ifp->if_timer = 0;
888                                 ifp->if_oerrors++;
889                         }
890                         break;
891
892                 case ISQ_RX_MISS_EVENT:
893                         ifp->if_ierrors+=(status>>6);
894                         break;
895
896                 case ISQ_TX_COL_EVENT:
897                         ifp->if_collisions+=(status>>6);
898                         break;
899                 }
900         }
901
902         if (!(ifp->if_flags & IFF_OACTIVE)) {
903                 cs_start(ifp);
904         }
905 }
906
907 /*
908  * Save the data in buffer
909  */
910
911 static void
912 cs_write_mbufs( struct cs_softc *sc, struct mbuf *m )
913 {
914         int len;
915         struct mbuf *mp;
916         unsigned char *data, *buf;
917
918         for (mp=m, buf=sc->buffer, sc->buf_len=0; mp != NULL; mp=mp->m_next) {
919                 len = mp->m_len;
920
921                 /*
922                  * Ignore empty parts
923                  */
924                 if (!len)
925                 continue;
926
927                 /*
928                  * Find actual data address
929                  */
930                 data = mtod(mp, caddr_t);
931
932                 bcopy((caddr_t) data, (caddr_t) buf, len);
933                 buf += len;
934                 sc->buf_len += len;
935         }
936 }
937
938
939 static void
940 cs_xmit_buf( struct cs_softc *sc )
941 {
942         outsw(sc->nic_addr+TX_FRAME_PORT, sc->buffer, (sc->buf_len+1)>>1);
943         sc->buf_len = 0;
944 }
945
946 static void
947 cs_start(struct ifnet *ifp)
948 {
949         int s, length;
950         struct mbuf *m, *mp;
951         struct cs_softc *sc = ifp->if_softc;
952
953         s = splimp();
954
955         for (;;) {
956                 if (sc->buf_len)
957                         length = sc->buf_len;
958                 else {
959                         IF_DEQUEUE( &ifp->if_snd, m );
960
961                         if (m==NULL) {
962                                 (void) splx(s);
963                                 return;
964                         }
965
966                         for (length=0, mp=m; mp != NULL; mp=mp->m_next)
967                                 length += mp->m_len;
968
969                         /* Skip zero-length packets */
970                         if (length == 0) {
971                                 m_freem(m);
972                                 continue;
973                         }
974
975                         cs_write_mbufs(sc, m);
976
977                         if (ifp->if_bpf) {
978                                 bpf_mtap(ifp, m);
979                         }
980
981                         m_freem(m);
982                 }
983
984                 /*
985                  * Issue a SEND command
986                  */
987                 outw(sc->nic_addr+TX_CMD_PORT, sc->send_cmd);
988                 outw(sc->nic_addr+TX_LEN_PORT, length );
989
990                 /*
991                  * If there's no free space in the buffer then leave
992                  * this packet for the next time: indicate output active
993                  * and return.
994                  */
995                 if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) {
996                         ifp->if_timer = sc->buf_len;
997                         (void) splx(s);
998                         ifp->if_flags |= IFF_OACTIVE;
999                         return;
1000                 }
1001
1002                 cs_xmit_buf(sc);
1003
1004                 /*
1005                  * Set the watchdog timer in case we never hear
1006                  * from board again. (I don't know about correct
1007                  * value for this timeout)
1008                  */
1009                 ifp->if_timer = length;
1010
1011                 (void) splx(s);
1012                 ifp->if_flags |= IFF_OACTIVE;
1013                 return;
1014         }
1015 }
1016
1017 /*
1018  * Stop everything on the interface
1019  */
1020 static void
1021 cs_stop(struct cs_softc *sc)
1022 {
1023         int s = splimp();
1024
1025         cs_writereg(sc->nic_addr, PP_RxCFG, 0);
1026         cs_writereg(sc->nic_addr, PP_TxCFG, 0);
1027         cs_writereg(sc->nic_addr, PP_BufCFG, 0);
1028         cs_writereg(sc->nic_addr, PP_BusCTL, 0);
1029
1030         sc->arpcom.ac_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1031         sc->arpcom.ac_if.if_timer = 0;
1032
1033         (void) splx(s);
1034 }
1035
1036 /*
1037  * Reset the interface
1038  */
1039 static void
1040 cs_reset(struct cs_softc *sc)
1041 {
1042         cs_stop(sc);
1043         cs_init(sc);
1044 }
1045
1046 static void
1047 cs_setmode(struct cs_softc *sc)
1048 {
1049         struct ifnet *ifp = &(sc->arpcom.ac_if);
1050         int rx_ctl;
1051
1052         /* Stop the receiver while changing filters */
1053         cs_writereg(sc->nic_addr, PP_LineCTL, 
1054                         cs_readreg(sc->nic_addr, PP_LineCTL) & ~SERIAL_RX_ON);
1055
1056         if (ifp->if_flags & IFF_PROMISC) {
1057                 /* Turn on promiscuous mode. */
1058                 rx_ctl = RX_OK_ACCEPT | RX_PROM_ACCEPT;
1059         } else {
1060                 if (ifp->if_flags & IFF_MULTICAST) {
1061                         /* Allow receiving frames with multicast addresses */
1062                         rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT |
1063                                  RX_OK_ACCEPT | RX_MULTCAST_ACCEPT;
1064                         /*
1065                          * Here the reconfiguration of chip's multicast
1066                          * filters should be done but I've no idea about
1067                          * hash transformation in this chip. If you can
1068                          * add this code or describe me the transformation
1069                          * I'd be very glad.
1070                          */
1071                 } else {
1072                         /*
1073                          * Receive only good frames addressed for us and
1074                          * good broadcasts.
1075                          */
1076                         rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT |
1077                                  RX_OK_ACCEPT;
1078                 }
1079         }
1080
1081         /* Set up the filter */
1082         cs_writereg(sc->nic_addr, PP_RxCTL, RX_DEF_ACCEPT | rx_ctl);
1083
1084         /* Turn on receiver */
1085         cs_writereg(sc->nic_addr, PP_LineCTL,
1086                         cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_RX_ON);
1087 }
1088
1089 static int
1090 cs_ioctl(register struct ifnet *ifp, u_long command, caddr_t data,
1091     struct ucred *cr)
1092 {
1093         struct cs_softc *sc=ifp->if_softc;
1094         struct ifreq *ifr = (struct ifreq *)data;
1095         int s,error=0;
1096
1097 #ifdef CS_DEBUG
1098         printf("%s: ioctl(%lx)\n",sc->arpcom.ac_if.if_xname, command);
1099 #endif
1100
1101         s=splimp();
1102
1103         switch (command) {
1104         case SIOCSIFADDR:
1105         case SIOCGIFADDR:
1106         case SIOCSIFMTU:
1107                 ether_ioctl(ifp, command, data);
1108                 break;
1109
1110         case SIOCSIFFLAGS:
1111                 /*
1112                  * Switch interface state between "running" and
1113                  * "stopped", reflecting the UP flag.
1114                  */
1115                 if (sc->arpcom.ac_if.if_flags & IFF_UP) {
1116                         if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)==0) {
1117                                 cs_init(sc);
1118                         }
1119                 } else {
1120                         if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)!=0) {
1121                                 cs_stop(sc);
1122                         }
1123                 }
1124                 /*
1125                  * Promiscuous and/or multicast flags may have changed,
1126                  * so reprogram the multicast filter and/or receive mode.
1127                  *
1128                  * See note about multicasts in cs_setmode
1129                  */
1130                 cs_setmode(sc);
1131                 break;
1132
1133         case SIOCADDMULTI:
1134         case SIOCDELMULTI:
1135             /*
1136              * Multicast list has changed; set the hardware filter
1137              * accordingly.
1138              *
1139              * See note about multicasts in cs_setmode
1140              */
1141             cs_setmode(sc);
1142             error = 0;
1143             break;
1144
1145         case SIOCSIFMEDIA:
1146         case SIOCGIFMEDIA:
1147                 error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
1148                 break;
1149
1150         default:
1151                 error = EINVAL;
1152         }
1153
1154         (void) splx(s);
1155         return error;
1156 }
1157
1158 /*
1159  * Device timeout/watchdog routine. Entered if the device neglects to
1160  * generate an interrupt after a transmit has been started on it.
1161  */
1162 static void
1163 cs_watchdog(struct ifnet *ifp)
1164 {
1165         struct cs_softc *sc = ifp->if_softc;
1166
1167         ifp->if_oerrors++;
1168         log(LOG_ERR, "%s: device timeout\n", ifp->if_xname);
1169
1170         /* Reset the interface */
1171         if (ifp->if_flags & IFF_UP)
1172                 cs_reset(sc);
1173         else
1174                 cs_stop(sc);
1175 }
1176
1177 static int
1178 cs_mediachange(struct ifnet *ifp)
1179 {
1180         struct cs_softc *sc = ifp->if_softc;
1181         struct ifmedia *ifm = &sc->media;
1182
1183         if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1184                 return EINVAL;
1185
1186         return cs_mediaset(sc, ifm->ifm_media);
1187 }
1188
1189 static void
1190 cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1191 {
1192         int line_status;
1193         struct cs_softc *sc = ifp->if_softc;
1194
1195         ifmr->ifm_active = IFM_ETHER;
1196         line_status = cs_readreg(sc->nic_addr, PP_LineST);
1197         if (line_status & TENBASET_ON) {
1198                 ifmr->ifm_active |= IFM_10_T;
1199                 if (sc->chip_type != CS8900) {
1200                         if (cs_readreg(sc->nic_addr, PP_AutoNegST) & FDX_ACTIVE)
1201                                 ifmr->ifm_active |= IFM_FDX;
1202                         if (cs_readreg(sc->nic_addr, PP_AutoNegST) & HDX_ACTIVE)
1203                                 ifmr->ifm_active |= IFM_HDX;
1204                 }
1205                 ifmr->ifm_status = IFM_AVALID;
1206                 if (line_status & LINK_OK)
1207                         ifmr->ifm_status |= IFM_ACTIVE;
1208         } else {
1209                 if (line_status & AUI_ON) {
1210                         cs_writereg(sc->nic_addr, PP_SelfCTL,
1211                                     cs_readreg(sc->nic_addr, PP_SelfCTL) |
1212                                     HCB1_ENBL);
1213                         if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^
1214                             (cs_readreg(sc->nic_addr, PP_SelfCTL)&HCB1))
1215                                 ifmr->ifm_active |= IFM_10_2;
1216                         else
1217                                 ifmr->ifm_active |= IFM_10_5;
1218                 }
1219         }
1220 }
1221
1222 static int
1223 cs_mediaset(struct cs_softc *sc, int media)
1224 {
1225         int error;
1226
1227         /* Stop the receiver & transmitter */
1228         cs_writereg(sc->nic_addr, PP_LineCTL,
1229                     cs_readreg(sc->nic_addr, PP_LineCTL) &
1230                     ~(SERIAL_RX_ON | SERIAL_TX_ON));
1231
1232 #ifdef CS_DEBUG
1233         printf("%s: cs_setmedia(%x)\n",sc->arpcom.ac_if.if_xname, media);
1234 #endif
1235
1236         switch (IFM_SUBTYPE(media)) {
1237         default:
1238         case IFM_AUTO:
1239                 if ((error=enable_tp(sc))==0)
1240                         error = cs_duplex_auto(sc);
1241                 else if ((error=enable_bnc(sc)) != 0)
1242                         error = enable_aui(sc);
1243                 break;
1244         case IFM_10_T:
1245                 if ((error=enable_tp(sc)) != 0)
1246                         break;
1247                 if (media & IFM_FDX)
1248                         cs_duplex_full(sc);
1249                 else if (media & IFM_HDX)
1250                         cs_duplex_half(sc);
1251                 else
1252                         error = cs_duplex_auto(sc);
1253                 break;
1254         case IFM_10_2:
1255                 error = enable_bnc(sc);
1256                 break;
1257         case IFM_10_5:
1258                 error = enable_aui(sc);
1259                 break;
1260         }
1261
1262         /*
1263          * Turn the transmitter & receiver back on
1264          */
1265         cs_writereg(sc->nic_addr, PP_LineCTL,
1266                     cs_readreg( sc->nic_addr, PP_LineCTL ) |
1267                     SERIAL_RX_ON | SERIAL_TX_ON); 
1268
1269         return error;
1270 }