if_cs.c revision 50477
1238438Sdteske/*
2238438Sdteske * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko.
3238438Sdteske * All rights reserved.
4252982Sdteske *
5238438Sdteske * Redistribution and use in source and binary forms, with or without
6238438Sdteske * modification, are permitted provided that the following conditions
7238438Sdteske * are met:
8238438Sdteske * 1. Redistributions of source code must retain the above copyright
9238438Sdteske *    notice unmodified, this list of conditions, and the following
10238438Sdteske *    disclaimer.
11238438Sdteske * 2. Redistributions in binary form must reproduce the above copyright
12238438Sdteske *    notice, this list of conditions and the following disclaimer in the
13238438Sdteske *    documentation and/or other materials provided with the distribution.
14238438Sdteske *
15238438Sdteske * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16252987Sdteske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17238438Sdteske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18238438Sdteske * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19238438Sdteske * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20240797Sdteske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21238438Sdteske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22238438Sdteske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23238438Sdteske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24238438Sdteske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25238438Sdteske * SUCH DAMAGE.
26238438Sdteske *
27238438Sdteske */
28238438Sdteske
29238438Sdteske/*
30238438Sdteske * $FreeBSD: head/sys/dev/cs/if_cs.c 50477 1999-08-28 01:08:13Z peter $
31240684Sdteske *
32241149Sdteske * Device driver for Crystal Semiconductor CS8920 based ethernet
33240684Sdteske *   adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997
34238438Sdteske */
35244675Sdteske
36244675Sdteske/* #define	 CS_DEBUG */
37244675Sdteske#include "cs.h"
38244675Sdteske#include "bpf.h"
39238438Sdteske
40238438Sdteske#include <sys/param.h>
41238438Sdteske#include <sys/systm.h>
42238438Sdteske#include <sys/malloc.h>
43238438Sdteske#include <sys/sockio.h>
44238438Sdteske#include <sys/kernel.h>
45238438Sdteske#include <sys/mbuf.h>
46238438Sdteske#include <sys/socket.h>
47238438Sdteske#include <sys/sysctl.h>
48238438Sdteske#include <sys/syslog.h>
49238438Sdteske
50238438Sdteske#include <net/if.h>
51238438Sdteske#include <net/if_arp.h>
52238438Sdteske#include <net/if_media.h>
53238438Sdteske#include <net/ethernet.h>
54238438Sdteske
55241019Sdteske#if NBPF > 0
56241019Sdteske#include <net/bpf.h>
57241019Sdteske#endif
58241019Sdteske
59241019Sdteske#include <machine/clock.h>
60241019Sdteske
61241019Sdteske#include <i386/isa/isa_device.h>
62241019Sdteske#include <i386/isa/if_csreg.h>
63241019Sdteske
64241019Sdteske#include "pnp.h"
65241019Sdteske
66238438Sdteske#if NPNP > 0
67238438Sdteske#include <i386/isa/pnp.h>
68238438Sdteske#endif
69238438Sdteske
70238438Sdteske#ifdef  CS_USE_64K_DMA
71238438Sdteske#define CS_DMA_BUFFER_SIZE 65536
72238438Sdteske#else
73238438Sdteske#define CS_DMA_BUFFER_SIZE 16384
74238438Sdteske#endif
75238438Sdteske
76238438Sdteske/*
77238438Sdteske * cs_softc: per line info and status
78238438Sdteske */
79238438Sdteskestatic struct cs_softc {
80238438Sdteske
81238438Sdteske        /* Ethernet common code */
82238438Sdteske        struct arpcom arpcom;
83238438Sdteske
84238438Sdteske        /* Configuration words from EEPROM */
85238438Sdteske        int auto_neg_cnf;               /* AutoNegotitation configuration */
86238438Sdteske	int adapter_cnf;                /* Adapter configuration */
87238438Sdteske        int isa_config;                 /* ISA configuration */
88238438Sdteske        int chip_type;			/* Type of chip */
89238438Sdteske
90238438Sdteske        struct ifmedia media;		/* Media information */
91238438Sdteske
92238438Sdteske        int nic_addr; 			/* Base IO address of card */
93238438Sdteske	int send_cmd;
94238438Sdteske        int line_ctl;                   /* */
95238438Sdteske        int send_underrun;
96238438Sdteske        void *recv_ring;
97238438Sdteske
98238438Sdteske        unsigned char *buffer;
99238438Sdteske        int buf_len;
100238438Sdteske
101238438Sdteske} cs_softc[NCS];
102238438Sdteske
103238438Sdteske#if NPNP > 0
104238438Sdteskestatic u_long	cs_unit = NCS;
105238438Sdteske#endif
106238438Sdteske
107238438Sdteskestatic int	cs_recv_delay = 570;
108238438SdteskeSYSCTL_INT(_machdep, OID_AUTO, cs_recv_delay, CTLFLAG_RW, &cs_recv_delay, 0, "");
109238438Sdteske
110238438Sdteskestatic int	cs_attach		__P((struct cs_softc *, int, int));
111238438Sdteskestatic int	cs_attach_isa		__P((struct isa_device *));
112238438Sdteskestatic void	cs_init			__P((void *));
113238438Sdteskestatic ointhand2_t	csintr;
114238438Sdteskestatic int	cs_ioctl		__P((struct ifnet *, u_long, caddr_t));
115238438Sdteskestatic int	cs_probe		__P((struct isa_device *));
116238438Sdteskestatic int	cs_cs89x0_probe		__P((struct cs_softc *,
117238438Sdteske					 u_int *, int *, int, int, int));
118238438Sdteskestatic void	cs_start		__P((struct ifnet *));
119238438Sdteskestatic void	cs_stop			__P((struct cs_softc *));
120238438Sdteskestatic void	cs_reset		__P((struct cs_softc *));
121258029Sdteskestatic void	cs_watchdog		__P((struct ifnet *));
122258029Sdteske
123238438Sdteskestatic int	cs_mediachange	__P((struct ifnet *));
124238438Sdteskestatic void	cs_mediastatus	__P((struct ifnet *, struct ifmediareq *));
125238438Sdteskestatic int      cs_mediaset	__P((struct cs_softc *, int));
126238438Sdteske
127238438Sdteskestatic void	cs_write_mbufs(struct cs_softc*, struct mbuf*);
128238438Sdteskestatic void	cs_xmit_buf(struct cs_softc*);
129238438Sdteskestatic int	cs_get_packet(struct cs_softc*);
130238438Sdteskestatic void	cs_setmode(struct cs_softc*);
131238438Sdteske
132238438Sdteskestatic int	get_eeprom_data(struct cs_softc *sc, int, int, int *);
133238438Sdteskestatic int	get_eeprom_cksum(int, int, int *);
134238438Sdteskestatic int	wait_eeprom_ready( struct cs_softc *);
135238438Sdteskestatic void	control_dc_dc( struct cs_softc *, int );
136238438Sdteskestatic int	send_test_pkt( struct cs_softc * );
137238438Sdteskestatic int	enable_tp(struct cs_softc *);
138252178Sdteskestatic int	enable_aui(struct cs_softc *);
139238438Sdteskestatic int	enable_bnc(struct cs_softc *);
140238438Sdteskestatic int      cs_duplex_auto(struct cs_softc *);
141238438Sdteske
142238438Sdteskestruct isa_driver csdriver = {
143238438Sdteske	cs_probe,
144238438Sdteske	cs_attach_isa,
145238438Sdteske	CS_NAME,
146238438Sdteske	0
147238438Sdteske};
148238438Sdteske
149241042Sdteskestatic int
150238438Sdteskeget_eeprom_data( struct cs_softc *sc, int off, int len, int *buffer)
151240783Sdteske{
152238438Sdteske	int i;
153238438Sdteske
154238438Sdteske#ifdef CS_DEBUG
155238438Sdteske	printf(CS_NAME":EEPROM data from %x for %x:\n", off,len);
156238438Sdteske#endif
157238438Sdteske
158238438Sdteske	for (i=0;i<len;i++) {
159238438Sdteske		if (wait_eeprom_ready(sc) < 0) return -1;
160238438Sdteske		/* Send command to EEPROM to read */
161238438Sdteske		cs_writereg(sc->nic_addr, PP_EECMD, (off+i)|EEPROM_READ_CMD );
162238438Sdteske		if (wait_eeprom_ready(sc)<0)
163238438Sdteske			return -1;
164238438Sdteske		buffer[i] = cs_readreg (sc->nic_addr, PP_EEData);
165238438Sdteske
166238438Sdteske#ifdef CS_DEBUG
167238438Sdteske		printf("%02x %02x ",(unsigned char)buffer[i],
168238438Sdteske					(unsigned char)buffer[i+1]);
169238438Sdteske#endif
170240798Sdteske	}
171238438Sdteske
172238438Sdteske#ifdef CS_DEBUG
173238438Sdteske	printf("\n");
174238438Sdteske#endif
175240783Sdteske
176238438Sdteske	return 0;
177238438Sdteske}
178238438Sdteske
179240797Sdteskestatic int
180238438Sdteskeget_eeprom_cksum(int off, int len, int *buffer)
181238438Sdteske{
182238438Sdteske	int i,cksum=0;
183238438Sdteske
184238438Sdteske	for (i=0;i<len;i++)
185238438Sdteske		cksum+=buffer[i];
186238438Sdteske	cksum &= 0xffff;
187238438Sdteske	if (cksum==0)
188238438Sdteske		return 0;
189238438Sdteske	return -1;
190238438Sdteske}
191238438Sdteske
192238438Sdteskestatic int
193238438Sdteskewait_eeprom_ready(struct cs_softc *sc)
194238438Sdteske{
195238438Sdteske	DELAY ( 30000 );	/* XXX should we do some checks here ? */
196238438Sdteske	return 0;
197238438Sdteske}
198238438Sdteske
199238438Sdteskestatic void
200238438Sdteskecontrol_dc_dc(struct cs_softc *sc, int on_not_off)
201238438Sdteske{
202238438Sdteske	unsigned int self_control = HCB1_ENBL;
203240783Sdteske
204238438Sdteske	if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0) ^ on_not_off)
205238438Sdteske		self_control |= HCB1;
206238438Sdteske	else
207238438Sdteske		self_control &= ~HCB1;
208238438Sdteske	cs_writereg( sc->nic_addr, PP_SelfCTL, self_control );
209238438Sdteske
210238438Sdteske	DELAY( 500000 );
211238438Sdteske}
212238438Sdteske
213238438Sdteske
214238438Sdteskestatic int
215238438Sdteskecs_duplex_auto(struct cs_softc *sc)
216238438Sdteske{
217238438Sdteske        int i, error=0, unit=sc->arpcom.ac_if.if_unit;
218238438Sdteske
219238438Sdteske        cs_writereg(sc->nic_addr, PP_AutoNegCTL,
220238438Sdteske                    RE_NEG_NOW | ALLOW_FDX | AUTO_NEG_ENABLE );
221252178Sdteske        for (i=0; cs_readreg(sc->nic_addr,PP_AutoNegST)&AUTO_NEG_BUSY; i++) {
222238438Sdteske                if (i > 40000) {
223238438Sdteske                        printf(CS_NAME"%1d: full/half duplex "
224238438Sdteske                               "auto negotiation timeout\n", unit);
225238438Sdteske			error = ETIMEDOUT;
226238438Sdteske                        break;
227238438Sdteske                }
228238438Sdteske                DELAY(1000);
229238438Sdteske        }
230238438Sdteske        DELAY( 1000000 );
231238438Sdteske	return error;
232238438Sdteske}
233238438Sdteske
234240783Sdteskestatic int
235238438Sdteskeenable_tp(struct cs_softc *sc)
236238438Sdteske{
237238438Sdteske	int unit = sc->arpcom.ac_if.if_unit;
238238438Sdteske
239238438Sdteske	cs_writereg(sc->nic_addr, PP_LineCTL, sc->line_ctl & ~AUI_ONLY);
240238438Sdteske	control_dc_dc(sc, 0);
241238438Sdteske	DELAY( 150000 );
242238438Sdteske
243238438Sdteske	if ((cs_readreg(sc->nic_addr, PP_LineST) & LINK_OK)==0) {
244238438Sdteske		printf(CS_NAME"%1d: failed to enable TP\n", unit);
245240783Sdteske                return EINVAL;
246238438Sdteske	}
247238438Sdteske
248238438Sdteske	return 0;
249238438Sdteske}
250238438Sdteske
251238438Sdteske/*
252238438Sdteske * XXX This was rewritten from Linux driver without any tests.
253238438Sdteske */
254238438Sdteskestatic int
255238438Sdteskesend_test_pkt(struct cs_softc *sc)
256238438Sdteske{
257238438Sdteske	char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
258238438Sdteske				0, 46,  /* A 46 in network order */
259238438Sdteske				0, 0,   /* DSAP=0 & SSAP=0 fields */
260241019Sdteske				0xf3, 0 /* Control (Test Req + P bit set) */ };
261238438Sdteske	int i;
262238438Sdteske	u_char ether_address_backup[ETHER_ADDR_LEN];
263238438Sdteske
264238438Sdteske	for (i = 0; i < ETHER_ADDR_LEN; i++) {
265238438Sdteske		ether_address_backup[i] = sc->arpcom.ac_enaddr[i];
266238438Sdteske	}
267241019Sdteske
268241019Sdteske	cs_writereg(sc->nic_addr, PP_LineCTL,
269241019Sdteske		cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_TX_ON );
270238438Sdteske	bcopy(test_packet,
271238438Sdteske			sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
272238438Sdteske	bcopy(test_packet+ETHER_ADDR_LEN,
273238438Sdteske			sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
274238438Sdteske	outw(sc->nic_addr + TX_CMD_PORT, sc->send_cmd);
275240863Sdteske	outw(sc->nic_addr + TX_LEN_PORT, sizeof(test_packet));
276238438Sdteske
277238438Sdteske	/* Wait for chip to allocate memory */
278238438Sdteske	DELAY(50000);
279238438Sdteske	if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) {
280238438Sdteske		for (i = 0; i < ETHER_ADDR_LEN; i++) {
281238438Sdteske			sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
282238438Sdteske		}
283238438Sdteske		return 0;
284238438Sdteske	}
285238438Sdteske
286238438Sdteske	outsw(sc->nic_addr + TX_FRAME_PORT, test_packet, sizeof(test_packet));
287238438Sdteske
288238438Sdteske	DELAY(30000);
289238438Sdteske
290238438Sdteske	if ((cs_readreg(sc->nic_addr,PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
291238438Sdteske		for (i = 0; i < ETHER_ADDR_LEN; i++) {
292238438Sdteske			sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
293238438Sdteske		}
294238438Sdteske		return 1;
295238438Sdteske	}
296238438Sdteske	for (i = 0; i < ETHER_ADDR_LEN; i++) {
297238438Sdteske		sc->arpcom.ac_enaddr[i] = ether_address_backup[i];
298238438Sdteske	}
299238438Sdteske	return 0;
300238438Sdteske}
301238438Sdteske
302238438Sdteske/*
303238438Sdteske * XXX This was rewritten from Linux driver without any tests.
304238438Sdteske */
305238438Sdteskestatic int
306238438Sdteskeenable_aui(struct cs_softc *sc)
307238438Sdteske{
308238438Sdteske	int unit = sc->arpcom.ac_if.if_unit;
309238438Sdteske
310238438Sdteske	control_dc_dc(sc, 0);
311238438Sdteske	cs_writereg(sc->nic_addr, PP_LineCTL,
312238438Sdteske		(sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY);
313238438Sdteske
314238438Sdteske	if (!send_test_pkt(sc)) {
315238438Sdteske		printf(CS_NAME"%1d failed to enable AUI\n", unit);
316238438Sdteske		return EINVAL;
317238438Sdteske        }
318238438Sdteske        return 0;
319238438Sdteske}
320238438Sdteske
321238438Sdteske/*
322238438Sdteske * XXX This was rewritten from Linux driver without any tests.
323238438Sdteske */
324238438Sdteskestatic int
325238438Sdteskeenable_bnc(struct cs_softc *sc)
326238438Sdteske{
327238438Sdteske	int unit = sc->arpcom.ac_if.if_unit;
328238438Sdteske
329238438Sdteske	control_dc_dc(sc, 1);
330238438Sdteske	cs_writereg(sc->nic_addr, PP_LineCTL,
331238438Sdteske		(sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY);
332238438Sdteske
333238438Sdteske	if (!send_test_pkt(sc)) {
334238438Sdteske		printf(CS_NAME"%1d failed to enable BNC\n", unit);
335238438Sdteske		return EINVAL;
336238438Sdteske        }
337238438Sdteske        return 0;
338238438Sdteske}
339238438Sdteske
340238438Sdteskestatic int
341238438Sdteskecs_cs89x0_probe(struct cs_softc *sc, u_int *dev_irq,
342238438Sdteske			int *dev_drq, int iobase, int unit, int flags)
343238438Sdteske{
344238438Sdteske	unsigned rev_type = 0;
345238438Sdteske	int i, irq=0;
346238438Sdteske	int eeprom_buff[CHKSUM_LEN];
347238438Sdteske	int chip_type, pp_isaint, pp_isadma;
348238438Sdteske	char chip_revision;
349238438Sdteske
350238438Sdteske	if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG) {
351238438Sdteske		/* Chip not detected. Let's try to reset it */
352238438Sdteske		if (bootverbose)
353238438Sdteske			printf(CS_NAME"%1d: trying to reset the chip.\n", unit);
354238438Sdteske		outw(iobase+ADD_PORT, PP_SelfCTL);
355238438Sdteske		i = inw(iobase+DATA_PORT);
356238438Sdteske		outw(iobase+ADD_PORT, PP_SelfCTL);
357238438Sdteske		outw(iobase+DATA_PORT, i | POWER_ON_RESET);
358238438Sdteske		if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG)
359238438Sdteske			return 0;
360238438Sdteske	}
361238438Sdteske
362238438Sdteske	outw(iobase+ADD_PORT, PP_ChipID);
363238438Sdteske	if (inw(iobase+DATA_PORT) != CHIP_EISA_ID_SIG)
364238438Sdteske		return 0;
365238438Sdteske
366238438Sdteske	rev_type = cs_readreg(iobase, PRODUCT_ID_ADD);
367238438Sdteske	chip_type = rev_type & ~REVISON_BITS;
368238438Sdteske	chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
369238438Sdteske
370238438Sdteske	sc->nic_addr = iobase;
371238438Sdteske	sc->chip_type = chip_type;
372238438Sdteske	if(chip_type==CS8900) {
373238438Sdteske		pp_isaint = PP_CS8900_ISAINT;
374238438Sdteske		pp_isadma = PP_CS8900_ISADMA;
375238438Sdteske		sc->send_cmd = TX_CS8900_AFTER_ALL;
376238438Sdteske	} else {
377238438Sdteske		pp_isaint = PP_CS8920_ISAINT;
378238438Sdteske		pp_isadma = PP_CS8920_ISADMA;
379238438Sdteske		sc->send_cmd = TX_CS8920_AFTER_ALL;
380238438Sdteske	}
381238438Sdteske
382238438Sdteske        /*
383238438Sdteske         * Clear some fields so that fail of EEPROM will left them clean
384238438Sdteske         */
385238438Sdteske        sc->auto_neg_cnf = 0;
386238438Sdteske        sc->adapter_cnf  = 0;
387238438Sdteske        sc->isa_config   = 0;
388238438Sdteske
389238438Sdteske	/*
390238438Sdteske	 * EEPROM
391238438Sdteske	 */
392238438Sdteske	if((cs_readreg(iobase, PP_SelfST) & EEPROM_PRESENT) == 0) {
393238438Sdteske		printf(CS_NAME"%1d: No EEPROM, assuming defaults.\n",
394238438Sdteske			unit);
395238438Sdteske	} else {
396238438Sdteske		if (get_eeprom_data(sc,START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) {
397238438Sdteske			 printf(CS_NAME"%1d: EEPROM read failed, "
398238438Sdteske				"assuming defaults..\n", unit);
399238438Sdteske		} else {
400238438Sdteske			if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) {
401238438Sdteske				printf( CS_NAME"%1d: EEPROM cheksum bad, "
402238438Sdteske					"assuming defaults..\n", unit );
403238438Sdteske			} else {
404238438Sdteske                                sc->auto_neg_cnf =
405238438Sdteske                                        eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
406238438Sdteske                                sc->adapter_cnf =
407238438Sdteske                                        eeprom_buff[ADAPTER_CNF_OFFSET/2];
408238438Sdteske                                sc->isa_config =
409238438Sdteske                                        eeprom_buff[ISA_CNF_OFFSET/2];
410238438Sdteske
411238438Sdteske                                for (i=0; i<ETHER_ADDR_LEN/2; i++) {
412238438Sdteske                                        sc->arpcom.ac_enaddr[i*2]=
413238438Sdteske                                                eeprom_buff[i];
414238438Sdteske                                        sc->arpcom.ac_enaddr[i*2+1]=
415238438Sdteske                                                eeprom_buff[i] >> 8;
416238438Sdteske                                }
417238438Sdteske
418238438Sdteske                                /*
419238438Sdteske                                 * If no interrupt specified (or "?"),
420238438Sdteske                                 * use what the board tells us.
421238438Sdteske                                 */
422238438Sdteske                                if (*dev_irq <= 0) {
423238438Sdteske                                        irq = sc->isa_config & INT_NO_MASK;
424238438Sdteske                                        if (chip_type==CS8900) {
425238438Sdteske						switch(irq) {
426238438Sdteske                                                case 0: irq=10; break;
427238438Sdteske                                                case 1: irq=11; break;
428238438Sdteske                                                case 2: irq=12; break;
429238438Sdteske                                                case 3: irq=5;  break;
430238438Sdteske                                                default: printf(CS_NAME"%1d: invalid irq in EEPROM.\n",unit);
431238438Sdteske						}
432238438Sdteske						if (irq!=0)
433238438Sdteske							*dev_irq=(u_short)(1<<irq);
434238438Sdteske					} else {
435238438Sdteske						if (irq!=0 && irq<=CS8920_NO_INTS)
436238438Sdteske							*dev_irq=(u_short)(1<<irq);
437238438Sdteske					}
438238438Sdteske                                }
439238438Sdteske			}
440238438Sdteske                }
441238438Sdteske        }
442238438Sdteske
443238438Sdteske        if ((irq=ffs(*dev_irq))) {
444238438Sdteske                irq--;
445238438Sdteske                if (chip_type == CS8900) {
446238438Sdteske			switch(irq) {
447238438Sdteske                        case  5: irq = 3; break;
448238438Sdteske                        case 10: irq = 0; break;
449238438Sdteske                        case 11: irq = 1; break;
450238438Sdteske                        case 12: irq = 2; break;
451238438Sdteske                        default: printf(CS_NAME"%1d: invalid irq\n", unit);
452238438Sdteske                                return 0;
453238438Sdteske			}
454240863Sdteske                } else {
455238438Sdteske                        if (irq > CS8920_NO_INTS) {
456238438Sdteske                                printf(CS_NAME"%1d: invalid irq\n", unit);
457241042Sdteske                                return 0;
458238438Sdteske                        }
459238438Sdteske                }
460238438Sdteske                cs_writereg(iobase, pp_isaint, irq);
461238438Sdteske	} else {
462238438Sdteske	       	printf(CS_NAME"%1d: invalid irq\n", unit);
463238438Sdteske                return 0;
464238438Sdteske        }
465238438Sdteske
466238438Sdteske        /*
467238438Sdteske         * Temporary disabled
468238438Sdteske         *
469238438Sdteske        if (drq>0)
470238438Sdteske		cs_writereg(iobase, pp_isadma, drq);
471238438Sdteske	else {
472238438Sdteske		printf( CS_NAME"%1d: incorrect drq\n", unit );
473238438Sdteske		return 0;
474238438Sdteske	}
475238438Sdteske        */
476238438Sdteske
477238438Sdteske	if (bootverbose)
478238438Sdteske		 printf(CS_NAME"%1d: model CS89%c0%s rev %c\n"
479238438Sdteske			CS_NAME"%1d: media%s%s%s\n"
480238438Sdteske			CS_NAME"%1d: irq %d drq %d\n",
481238438Sdteske			unit,
482238438Sdteske			chip_type==CS8900 ? '0' : '2',
483238438Sdteske			chip_type==CS8920M ? "M" : "",
484238438Sdteske			chip_revision,
485238438Sdteske			unit,
486238438Sdteske			(sc->adapter_cnf & A_CNF_10B_T) ? " TP"  : "",
487238438Sdteske			(sc->adapter_cnf & A_CNF_AUI)   ? " AUI" : "",
488238438Sdteske			(sc->adapter_cnf & A_CNF_10B_2) ? " BNC" : "",
489238438Sdteske			unit, (int)*dev_irq, (int)*dev_drq);
490238438Sdteske
491240783Sdteske        if ((sc->adapter_cnf & A_CNF_EXTND_10B_2) &&
492238438Sdteske            (sc->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
493238438Sdteske                sc->line_ctl = LOW_RX_SQUELCH;
494238438Sdteske        else
495238438Sdteske                sc->line_ctl = 0;
496238438Sdteske
497238438Sdteske
498238438Sdteske	return PP_ISAIOB;
499238438Sdteske}
500240783Sdteske
501238438Sdteske/*
502238438Sdteske * Determine if the device is present
503238438Sdteske *
504238438Sdteske *   on entry:
505238438Sdteske * 	a pointer to an isa_device struct
506238438Sdteske *   on exit:
507240783Sdteske *	NULL if device not found
508238438Sdteske *	or # of i/o addresses used (if found)
509238438Sdteske */
510238438Sdteskestatic int
511238438Sdteskecs_probe(struct isa_device *dev)
512238438Sdteske{
513238438Sdteske	int nports;
514238438Sdteske
515238438Sdteske	struct cs_softc *sc=&cs_softc[dev->id_unit];
516238438Sdteske
517238438Sdteske	nports=cs_cs89x0_probe(sc, &(dev->id_irq), &(dev->id_drq),
518238438Sdteske			(dev->id_iobase), (dev->id_unit), (dev->id_flags));
519238438Sdteske
520238438Sdteske	if (nports)
521238438Sdteske		return (nports);
522238438Sdteske
523238438Sdteske	return (0);
524238438Sdteske}
525238438Sdteske
526238438Sdteske/*
527238438Sdteske * Install the interface into kernel networking data structures
528238438Sdteske */
529238438Sdteskestatic int
530238438Sdteskecs_attach(struct cs_softc *sc, int unit, int flags)
531238438Sdteske{
532238438Sdteske        int media=0;
533238438Sdteske/*	struct cs_softc *sc = &cs_softc[dev->id_unit]; */
534238438Sdteske	struct ifnet *ifp = &(sc->arpcom.ac_if);
535238438Sdteske
536238438Sdteske	if (!ifp->if_name) {
537238438Sdteske		ifp->if_softc=sc;
538238438Sdteske		ifp->if_unit=unit;
539238438Sdteske		ifp->if_name=csdriver.name;
540238438Sdteske		ifp->if_output=ether_output;
541238438Sdteske		ifp->if_start=cs_start;
542238438Sdteske		ifp->if_ioctl=cs_ioctl;
543238438Sdteske		ifp->if_watchdog=cs_watchdog;
544238438Sdteske		ifp->if_init=cs_init;
545238438Sdteske		ifp->if_snd.ifq_maxlen= IFQ_MAXLEN;
546238438Sdteske		/*
547238438Sdteske                 *  MIB DATA
548238438Sdteske                 */
549238438Sdteske                /*
550238438Sdteske		ifp->if_linkmib=&sc->mibdata;
551238438Sdteske		ifp->if_linkmiblen=sizeof sc->mibdata;
552238438Sdteske                */
553238438Sdteske
554238438Sdteske		ifp->if_flags=(IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST );
555238438Sdteske
556238438Sdteske		/*
557238438Sdteske		 * this code still in progress (DMA support)
558238438Sdteske		 *
559238438Sdteske
560238438Sdteske		sc->recv_ring=malloc(CS_DMA_BUFFER_SIZE<<1, M_DEVBUF, M_NOWAIT);
561238438Sdteske		if (sc->recv_ring == NULL) {
562238438Sdteske			log(LOG_ERR,CS_NAME
563238438Sdteske			"%d: Couldn't allocate memory for NIC\n", unit);
564238438Sdteske			return(0);
565238438Sdteske		}
566238438Sdteske		if ((sc->recv_ring-(sc->recv_ring & 0x1FFFF))
567238438Sdteske		    < (128*1024-CS_DMA_BUFFER_SIZE))
568238438Sdteske		    sc->recv_ring+=16*1024;
569238438Sdteske
570238438Sdteske		*/
571238438Sdteske
572240863Sdteske		sc->buffer=malloc(ETHER_MAX_LEN-ETHER_CRC_LEN,M_DEVBUF,M_NOWAIT);
573238438Sdteske		if (sc->buffer == NULL) {
574238438Sdteske                        printf(CS_NAME"%d: Couldn't allocate memory for NIC\n",
575238438Sdteske                               unit);
576238438Sdteske                        return(0);
577238438Sdteske		}
578238438Sdteske
579238438Sdteske		/*
580238438Sdteske		 * Initialize the media structures.
581238438Sdteske		 */
582238438Sdteske		ifmedia_init(&sc->media, 0, cs_mediachange, cs_mediastatus);
583238438Sdteske
584238438Sdteske		if (sc->adapter_cnf & A_CNF_10B_T) {
585238438Sdteske			ifmedia_add(&sc->media, IFM_ETHER|IFM_10_T, 0, NULL);
586240783Sdteske			if (sc->chip_type != CS8900) {
587240783Sdteske				ifmedia_add(&sc->media,
588238438Sdteske					IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
589238438Sdteske				ifmedia_add(&sc->media,
590238438Sdteske					IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
591238438Sdteske			}
592238438Sdteske		}
593238438Sdteske
594238438Sdteske		if (sc->adapter_cnf & A_CNF_10B_2)
595238438Sdteske			ifmedia_add(&sc->media, IFM_ETHER|IFM_10_2, 0, NULL);
596238438Sdteske
597238438Sdteske		if (sc->adapter_cnf & A_CNF_AUI)
598238438Sdteske			ifmedia_add(&sc->media, IFM_ETHER|IFM_10_5, 0, NULL);
599238438Sdteske
600238438Sdteske                if (sc->adapter_cnf & A_CNF_MEDIA)
601238438Sdteske                        ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL);
602238438Sdteske
603238438Sdteske                /* Set default media from EEPROM */
604238438Sdteske                switch (sc->adapter_cnf & A_CNF_MEDIA_TYPE) {
605238438Sdteske                case A_CNF_MEDIA_AUTO:  media = IFM_ETHER|IFM_AUTO; break;
606238438Sdteske                case A_CNF_MEDIA_10B_T: media = IFM_ETHER|IFM_10_T; break;
607238438Sdteske                case A_CNF_MEDIA_10B_2: media = IFM_ETHER|IFM_10_2; break;
608238438Sdteske                case A_CNF_MEDIA_AUI:   media = IFM_ETHER|IFM_10_5; break;
609238438Sdteske                default: printf(CS_NAME"%d: adapter has no media\n", unit);
610238438Sdteske                }
611238438Sdteske                ifmedia_set(&sc->media, media);
612238438Sdteske		cs_mediaset(sc, media);
613238438Sdteske
614238438Sdteske		if_attach(ifp);
615238438Sdteske		cs_stop( sc );
616238438Sdteske		ether_ifattach(ifp);
617238438Sdteske	}
618238438Sdteske
619238438Sdteske	if (bootverbose)
620238438Sdteske		printf(CS_NAME"%d: ethernet address %6D\n",
621238438Sdteske		       ifp->if_unit, sc->arpcom.ac_enaddr, ":");
622238438Sdteske
623238438Sdteske#if NBPF > 0
624238438Sdteske	bpfattach(ifp, DLT_EN10MB, sizeof (struct ether_header));
625238438Sdteske#endif
626238438Sdteske	return 1;
627238438Sdteske}
628238438Sdteske
629244675Sdteskestatic int
630244675Sdteskecs_attach_isa(struct isa_device *dev)
631244675Sdteske{
632244675Sdteske        int unit=dev->id_unit;
633238438Sdteske        struct cs_softc *sc=&cs_softc[unit];
634        int flags=dev->id_flags;
635
636	dev->id_ointr = csintr;
637        return cs_attach(sc, unit, flags);
638}
639
640/*
641 * Initialize the board
642 */
643static void
644cs_init(void *xsc)
645{
646	struct cs_softc *sc=(struct cs_softc *)xsc;
647	struct ifnet *ifp = &sc->arpcom.ac_if;
648	int i, s, rx_cfg;
649
650	/* address not known */
651	if (TAILQ_EMPTY(&ifp->if_addrhead)) /* unlikely? XXX */
652		return;
653
654	/*
655	 * reset whatchdog timer
656	 */
657	ifp->if_timer=0;
658	sc->buf_len = 0;
659
660	s=splimp();
661
662	/*
663	 * Hardware initialization of cs
664	 */
665
666	/* Enable receiver and transmitter */
667	cs_writereg(sc->nic_addr, PP_LineCTL,
668		cs_readreg( sc->nic_addr, PP_LineCTL ) |
669		SERIAL_RX_ON | SERIAL_TX_ON);
670
671	/* Configure the receiver mode */
672	cs_setmode(sc);
673
674	/*
675	 * This defines what type of frames will cause interrupts
676	 * Bad frames should generate interrupts so that the driver
677	 * could track statistics of discarded packets
678	 */
679        rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL | RX_RUNT_ENBL |
680		 RX_EXTRA_DATA_ENBL;
681	if (sc->isa_config & STREAM_TRANSFER)
682		rx_cfg |= RX_STREAM_ENBL;
683	cs_writereg(sc->nic_addr, PP_RxCFG, rx_cfg);
684
685	cs_writereg(sc->nic_addr, PP_TxCFG, TX_LOST_CRS_ENBL |
686		    TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL |
687		    TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
688
689	cs_writereg(sc->nic_addr, PP_BufCFG, READY_FOR_TX_ENBL |
690		    RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL |
691		    TX_UNDERRUN_ENBL /*| RX_DMA_ENBL*/);
692
693        /* Write MAC address into IA filter */
694        for (i=0; i<ETHER_ADDR_LEN/2; i++)
695                cs_writereg(sc->nic_addr, PP_IA+i*2,
696                            sc->arpcom.ac_enaddr[i*2] |
697                            (sc->arpcom.ac_enaddr[i*2+1] << 8) );
698
699	/*
700	 * Now enable everything
701	 */
702/*
703#ifdef	CS_USE_64K_DMA
704	cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K);
705        #else
706
707        cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ);
708#endif
709*/
710	cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ);
711
712	/*
713	 * Set running and clear output active flags
714	 */
715	sc->arpcom.ac_if.if_flags |= IFF_RUNNING;
716	sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
717
718	/*
719	 * Start sending process
720	 */
721	cs_start(ifp);
722
723	(void) splx(s);
724}
725
726/*
727 * Get the packet from the board and send it to the upper layer
728 * via ether_input().
729 */
730static int
731cs_get_packet(struct cs_softc *sc)
732{
733	struct ifnet *ifp = &(sc->arpcom.ac_if);
734	int iobase = sc->nic_addr, status, length;
735	struct ether_header *eh;
736	struct mbuf *m;
737
738#ifdef CS_DEBUG
739	int i;
740#endif
741
742	status = inw(iobase + RX_FRAME_PORT);
743	length = inw(iobase + RX_FRAME_PORT);
744
745#ifdef CS_DEBUG
746	printf(CS_NAME"%1d: rcvd: stat %x, len %d\n",
747		ifp->if_unit, status, length);
748#endif
749
750	if (!(status & RX_OK)) {
751#ifdef CS_DEBUG
752		printf(CS_NAME"%1d: bad pkt stat %x\n", ifp->if_unit, status);
753#endif
754		ifp->if_ierrors++;
755		return -1;
756	}
757
758	MGETHDR(m, M_DONTWAIT, MT_DATA);
759	if (m==NULL)
760		return -1;
761
762	if (length > MHLEN) {
763		MCLGET(m, M_DONTWAIT);
764		if (!(m->m_flags & M_EXT)) {
765			m_freem(m);
766			return -1;
767		}
768	}
769
770	/* Initialize packet's header info */
771	m->m_pkthdr.rcvif = ifp;
772	m->m_pkthdr.len = length;
773	m->m_len = length;
774
775	/* Get the data */
776	insw(iobase + RX_FRAME_PORT, m->m_data, (length+1)>>1);
777
778	eh = mtod(m, struct ether_header *);
779
780#if NBPF > 0
781	if (ifp->if_bpf)
782		bpf_mtap(ifp, m);
783#endif
784
785#ifdef CS_DEBUG
786	for (i=0;i<length;i++)
787	     printf(" %02x",(unsigned char)*((char *)(m->m_data+i)));
788	printf( "\n" );
789#endif
790
791	if (status & (RX_IA | RX_BROADCAST) ||
792	    (ifp->if_flags & IFF_MULTICAST && status & RX_HASHED)) {
793		m->m_pkthdr.len -= sizeof(struct ether_header);
794		m->m_len -= sizeof(struct ether_header);
795		m->m_data += sizeof(struct ether_header);
796
797		/* Feed the packet to the upper layer */
798		ether_input(ifp, eh, m);
799
800		ifp->if_ipackets++;
801
802		if (length==ETHER_MAX_LEN-ETHER_CRC_LEN)
803                        DELAY( cs_recv_delay );
804	} else {
805		m_freem(m);
806	}
807
808	return 0;
809}
810
811/*
812 * Software calls interrupt handler
813 */
814static void
815csintr_sc(struct cs_softc *sc, int unit)
816{
817	struct ifnet *ifp = &(sc->arpcom.ac_if);
818	int status;
819
820#ifdef CS_DEBUG
821	printf(CS_NAME"%1d: Interrupt.\n", unit);
822#endif
823
824	while ((status=cs_readword(sc->nic_addr, ISQ_PORT))) {
825
826#ifdef CS_DEBUG
827		printf( CS_NAME"%1d:from ISQ: %04x\n", unit, status );
828#endif
829
830		switch (status & ISQ_EVENT_MASK) {
831                case ISQ_RECEIVER_EVENT:
832                        cs_get_packet(sc);
833                        break;
834
835                case ISQ_TRANSMITTER_EVENT:
836                        if (status & TX_OK)
837                                ifp->if_opackets++;
838                        else
839                                ifp->if_oerrors++;
840                        ifp->if_flags &= ~IFF_OACTIVE;
841                        ifp->if_timer = 0;
842                        break;
843
844                case ISQ_BUFFER_EVENT:
845                        if (status & READY_FOR_TX) {
846                                ifp->if_flags &= ~IFF_OACTIVE;
847                                ifp->if_timer = 0;
848                        }
849
850                        if (status & TX_UNDERRUN) {
851                                ifp->if_flags &= ~IFF_OACTIVE;
852                                ifp->if_timer = 0;
853                                ifp->if_oerrors++;
854                        }
855                        break;
856
857                case ISQ_RX_MISS_EVENT:
858                        ifp->if_ierrors+=(status>>6);
859                        break;
860
861                case ISQ_TX_COL_EVENT:
862                        ifp->if_collisions+=(status>>6);
863                        break;
864                }
865        }
866
867        if (!(ifp->if_flags & IFF_OACTIVE)) {
868                cs_start(ifp);
869        }
870}
871
872/*
873 * Handle interrupts
874 */
875static void
876csintr(int unit)
877{
878	struct cs_softc *sc = &cs_softc[unit];
879
880	csintr_sc(sc, unit);
881}
882
883/*
884 * Save the data in buffer
885 */
886
887static void
888cs_write_mbufs( struct cs_softc *sc, struct mbuf *m )
889{
890	int len;
891	struct mbuf *mp;
892	unsigned char *data, *buf;
893
894	for (mp=m, buf=sc->buffer, sc->buf_len=0; mp != NULL; mp=mp->m_next) {
895		len = mp->m_len;
896
897		/*
898		 * Ignore empty parts
899		 */
900		if (!len)
901		continue;
902
903		/*
904		 * Find actual data address
905		 */
906		data = mtod(mp, caddr_t);
907
908		bcopy((caddr_t) data, (caddr_t) buf, len);
909		buf += len;
910		sc->buf_len += len;
911	}
912}
913
914
915static void
916cs_xmit_buf( struct cs_softc *sc )
917{
918	outsw(sc->nic_addr+TX_FRAME_PORT, sc->buffer, (sc->buf_len+1)>>1);
919	sc->buf_len = 0;
920}
921
922static void
923cs_start(struct ifnet *ifp)
924{
925	int s, length;
926	struct mbuf *m, *mp;
927	struct cs_softc *sc = ifp->if_softc;
928
929	s = splimp();
930
931	for (;;) {
932		if (sc->buf_len)
933			length = sc->buf_len;
934		else {
935			IF_DEQUEUE( &ifp->if_snd, m );
936
937			if (m==NULL) {
938				(void) splx(s);
939				return;
940			}
941
942			for (length=0, mp=m; mp != NULL; mp=mp->m_next)
943				length += mp->m_len;
944
945			/* Skip zero-length packets */
946			if (length == 0) {
947				m_freem(m);
948				continue;
949			}
950
951			cs_write_mbufs(sc, m);
952
953#if NBPF > 0
954			if (ifp->if_bpf) {
955				bpf_mtap(ifp, m);
956			}
957#endif
958
959			m_freem(m);
960		}
961
962		/*
963		 * Issue a SEND command
964		 */
965		outw(sc->nic_addr+TX_CMD_PORT, sc->send_cmd);
966		outw(sc->nic_addr+TX_LEN_PORT, length );
967
968		/*
969		 * If there's no free space in the buffer then leave
970		 * this packet for the next time: indicate output active
971		 * and return.
972		 */
973		if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) {
974			ifp->if_timer = sc->buf_len;
975			(void) splx(s);
976			ifp->if_flags |= IFF_OACTIVE;
977			return;
978		}
979
980               	cs_xmit_buf(sc);
981
982		/*
983		 * Set the watchdog timer in case we never hear
984		 * from board again. (I don't know about correct
985		 * value for this timeout)
986		 */
987		ifp->if_timer = length;
988
989		(void) splx(s);
990		ifp->if_flags |= IFF_OACTIVE;
991		return;
992	}
993}
994
995/*
996 * Stop everything on the interface
997 */
998static void
999cs_stop(struct cs_softc *sc)
1000{
1001	int s = splimp();
1002
1003	cs_writereg(sc->nic_addr, PP_RxCFG, 0);
1004	cs_writereg(sc->nic_addr, PP_TxCFG, 0);
1005	cs_writereg(sc->nic_addr, PP_BufCFG, 0);
1006	cs_writereg(sc->nic_addr, PP_BusCTL, 0);
1007
1008	sc->arpcom.ac_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1009	sc->arpcom.ac_if.if_timer = 0;
1010
1011	(void) splx(s);
1012}
1013
1014/*
1015 * Reset the interface
1016 */
1017static void
1018cs_reset(struct cs_softc *sc)
1019{
1020	cs_stop(sc);
1021	cs_init(sc);
1022}
1023
1024static void
1025cs_setmode(struct cs_softc *sc)
1026{
1027	struct ifnet *ifp = &(sc->arpcom.ac_if);
1028	int rx_ctl;
1029
1030	/* Stop the receiver while changing filters */
1031	cs_writereg(sc->nic_addr, PP_LineCTL,
1032			cs_readreg(sc->nic_addr, PP_LineCTL) & ~SERIAL_RX_ON);
1033
1034	if (ifp->if_flags & IFF_PROMISC) {
1035		/* Turn on promiscuous mode. */
1036		rx_ctl = RX_OK_ACCEPT | RX_PROM_ACCEPT;
1037	} else {
1038		if (ifp->if_flags & IFF_MULTICAST) {
1039			/* Allow receiving frames with multicast addresses */
1040			rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT |
1041				 RX_OK_ACCEPT | RX_MULTCAST_ACCEPT;
1042			/*
1043			 * Here the reconfiguration of chip's multicast
1044			 * filters should be done but I've no idea about
1045			 * hash transformation in this chip. If you can
1046			 * add this code or describe me the transformation
1047			 * I'd be very glad.
1048			 */
1049		} else {
1050			/*
1051			 * Receive only good frames addressed for us and
1052			 * good broadcasts.
1053			 */
1054			rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT |
1055				 RX_OK_ACCEPT;
1056		}
1057	}
1058
1059	/* Set up the filter */
1060	cs_writereg(sc->nic_addr, PP_RxCTL, RX_DEF_ACCEPT | rx_ctl);
1061
1062	/* Turn on receiver */
1063	cs_writereg(sc->nic_addr, PP_LineCTL,
1064			cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_RX_ON);
1065}
1066
1067static int
1068cs_ioctl(register struct ifnet *ifp, u_long command, caddr_t data)
1069{
1070	struct cs_softc *sc=ifp->if_softc;
1071	struct ifreq *ifr = (struct ifreq *)data;
1072	int s,error=0;
1073
1074#ifdef CS_DEBUG
1075	printf(CS_NAME"%d: ioctl(%x)\n",sc->arpcom.ac_if.if_unit,command);
1076#endif
1077
1078	s=splimp();
1079
1080	switch (command) {
1081	case SIOCSIFADDR:
1082	case SIOCGIFADDR:
1083	case SIOCSIFMTU:
1084		ether_ioctl(ifp, command, data);
1085		break;
1086
1087	case SIOCSIFFLAGS:
1088		/*
1089		 * Switch interface state between "running" and
1090		 * "stopped", reflecting the UP flag.
1091                 */
1092                if (sc->arpcom.ac_if.if_flags & IFF_UP) {
1093                        if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)==0) {
1094                                cs_init(sc);
1095                        }
1096                } else {
1097                        if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)!=0) {
1098                                cs_stop(sc);
1099                        }
1100		}
1101		/*
1102		 * Promiscuous and/or multicast flags may have changed,
1103		 * so reprogram the multicast filter and/or receive mode.
1104		 *
1105		 * See note about multicasts in cs_setmode
1106		 */
1107		cs_setmode(sc);
1108		break;
1109
1110	case SIOCADDMULTI:
1111	case SIOCDELMULTI:
1112	    /*
1113	     * Multicast list has changed; set the hardware filter
1114	     * accordingly.
1115	     *
1116	     * See note about multicasts in cs_setmode
1117	     */
1118	    cs_setmode(sc);
1119	    error = 0;
1120	    break;
1121
1122        case SIOCSIFMEDIA:
1123        case SIOCGIFMEDIA:
1124                error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
1125                break;
1126
1127        default:
1128		error = EINVAL;
1129        }
1130
1131	(void) splx(s);
1132	return error;
1133}
1134
1135/*
1136 * Device timeout/watchdog routine. Entered if the device neglects to
1137 * generate an interrupt after a transmit has been started on it.
1138 */
1139static void
1140cs_watchdog(struct ifnet *ifp)
1141{
1142	struct cs_softc *sc = &cs_softc[ifp->if_unit];
1143
1144	ifp->if_oerrors++;
1145	log(LOG_ERR, CS_NAME"%d: device timeout\n", ifp->if_unit);
1146
1147	/* Reset the interface */
1148	if (ifp->if_flags & IFF_UP)
1149		cs_reset(sc);
1150	else
1151		cs_stop(sc);
1152}
1153
1154static int
1155cs_mediachange(struct ifnet *ifp)
1156{
1157	struct cs_softc *sc = ifp->if_softc;
1158	struct ifmedia *ifm = &sc->media;
1159
1160	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1161		return EINVAL;
1162
1163	return cs_mediaset(sc, ifm->ifm_media);
1164}
1165
1166static void
1167cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1168{
1169	int line_status;
1170	struct cs_softc *sc = ifp->if_softc;
1171
1172	ifmr->ifm_active = IFM_ETHER;
1173	line_status = cs_readreg(sc->nic_addr, PP_LineST);
1174	if (line_status & TENBASET_ON) {
1175		ifmr->ifm_active |= IFM_10_T;
1176		if (sc->chip_type != CS8900) {
1177			if (cs_readreg(sc->nic_addr, PP_AutoNegST) & FDX_ACTIVE)
1178				ifmr->ifm_active |= IFM_FDX;
1179			if (cs_readreg(sc->nic_addr, PP_AutoNegST) & HDX_ACTIVE)
1180				ifmr->ifm_active |= IFM_HDX;
1181		}
1182		ifmr->ifm_status = IFM_AVALID;
1183		if (line_status & LINK_OK)
1184			ifmr->ifm_status |= IFM_ACTIVE;
1185	} else {
1186		if (line_status & AUI_ON) {
1187			cs_writereg(sc->nic_addr, PP_SelfCTL,
1188				    cs_readreg(sc->nic_addr, PP_SelfCTL) |
1189				    HCB1_ENBL);
1190			if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^
1191			    (cs_readreg(sc->nic_addr, PP_SelfCTL)&HCB1))
1192				ifmr->ifm_active |= IFM_10_2;
1193			else
1194				ifmr->ifm_active |= IFM_10_5;
1195		}
1196	}
1197}
1198
1199static int
1200cs_mediaset(struct cs_softc *sc, int media)
1201{
1202        int error;
1203
1204	/* Stop the receiver & transmitter */
1205	cs_writereg(sc->nic_addr, PP_LineCTL,
1206                    cs_readreg(sc->nic_addr, PP_LineCTL) &
1207		    ~(SERIAL_RX_ON | SERIAL_TX_ON));
1208
1209#ifdef CS_DEBUG
1210	printf(CS_NAME"%d: cs_setmedia(%x)\n",sc->arpcom.ac_if.if_unit,media);
1211#endif
1212
1213	switch (IFM_SUBTYPE(media)) {
1214	default:
1215	case IFM_AUTO:
1216		if ((error=enable_tp(sc))==0)
1217			error = cs_duplex_auto(sc);
1218		else if ((error=enable_bnc(sc)) != 0)
1219			error = enable_aui(sc);
1220		break;
1221	case IFM_10_T:
1222		if ((error=enable_tp(sc)) != 0)
1223			break;
1224		if (media & IFM_FDX)
1225			cs_duplex_full(sc);
1226		else if (media & IFM_HDX)
1227			cs_duplex_half(sc);
1228		else
1229			error = cs_duplex_auto(sc);
1230		break;
1231	case IFM_10_2:
1232		error = enable_bnc(sc);
1233		break;
1234	case IFM_10_5:
1235		error = enable_aui(sc);
1236		break;
1237	}
1238
1239	/*
1240	 * Turn the transmitter & receiver back on
1241	 */
1242	cs_writereg(sc->nic_addr, PP_LineCTL,
1243		    cs_readreg( sc->nic_addr, PP_LineCTL ) |
1244		    SERIAL_RX_ON | SERIAL_TX_ON);
1245
1246	return error;
1247}
1248
1249
1250#if NPNP > 0
1251
1252static struct cspnp_ids {
1253	u_long	vend_id;
1254	char 	*id_str;
1255} cspnp_ids[]= {
1256	{ 0x4060630e, "CSC6040" },
1257	{ 0x10104d24, "IBM EtherJet" },
1258	{ 0 }
1259};
1260
1261static char *cs_pnp_probe(u_long, u_long);
1262static void cs_pnp_attach(u_long, u_long, char *, struct isa_device *);
1263
1264struct pnp_device cs_pnp = {
1265	"CS8920 based PnP Ethernet",
1266	cs_pnp_probe,
1267	cs_pnp_attach,
1268	&cs_unit,
1269	&net_imask	/* imask */
1270};
1271
1272DATA_SET (pnpdevice_set, cs_pnp);
1273
1274struct csintr_list {
1275	struct cs_softc *sc;
1276	int unit;
1277	struct csintr_list *next;
1278};
1279
1280static struct csintr_list *csintr_head;
1281
1282static void csintr_pnp_add(struct cs_softc *sc, int unit);
1283static void csintr_pnp(int unit);
1284
1285static void
1286csintr_pnp_add(struct cs_softc *sc, int unit)
1287{
1288    struct csintr_list *intr;
1289
1290    if (!sc) return;
1291
1292    intr = malloc (sizeof (*intr), M_DEVBUF, M_WAITOK);
1293    if (!intr) return;
1294
1295    intr->sc = sc;
1296    intr->unit = unit;
1297    intr->next = csintr_head;
1298    csintr_head = intr;
1299}
1300
1301/*
1302 * Interrupt handler for PNP installed card
1303 * We have to find the number of the card.
1304 */
1305static void
1306csintr_pnp(int unit)
1307{
1308    struct csintr_list *intr;
1309
1310    for (intr=csintr_head; intr; intr=intr->next) {
1311	    if (intr->unit == unit)
1312		csintr_sc(intr->sc, unit);
1313		break;
1314	}
1315}
1316
1317static char *
1318cs_pnp_probe(u_long csn, u_long vend_id)
1319{
1320    struct cspnp_ids *ids;
1321    char	     *s=NULL;
1322
1323    for(ids = cspnp_ids; ids->vend_id != 0; ids++) {
1324	if (vend_id == ids->vend_id) {
1325	    s = ids->id_str;
1326	    break;
1327	}
1328    }
1329
1330    if (s) {
1331	struct pnp_cinfo d;
1332	int ldn = 0;
1333
1334	read_pnp_parms(&d, ldn);
1335	if (d.enable == 0) {
1336	    printf("This is a %s, but LDN %d is disabled\n", s, ldn);
1337	    return NULL ;
1338	}
1339	return s;
1340    }
1341
1342    return NULL ;
1343}
1344
1345static void
1346cs_pnp_attach(u_long csn, u_long vend_id, char *name,
1347	struct isa_device *dev)
1348{
1349
1350    struct pnp_cinfo d;
1351    int	ldn = 0;
1352    int iobase, unit, flags;
1353    u_int irq;
1354    int drq;
1355    struct cs_softc *sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
1356
1357    if (read_pnp_parms ( &d , ldn ) == 0 ) {
1358	printf("failed to read pnp parms\n");
1359	return;
1360    }
1361
1362    write_pnp_parms( &d, ldn );
1363    enable_pnp_card();
1364
1365    iobase = dev->id_iobase = d.port[0];
1366    irq = dev->id_irq = (1 << d.irq[0] );
1367    drq = dev->id_drq = d.drq[0];
1368    dev->id_maddr = 0;
1369    dev->id_ointr = csintr_pnp;
1370    flags = dev->id_flags = 0;
1371    unit = dev->id_unit;
1372
1373    if (dev->id_driver == NULL) {
1374	dev->id_driver = &csdriver;
1375	dev->id_id = isa_compat_nextid();
1376    }
1377
1378    if (!sc) return;
1379
1380    bzero(sc, sizeof *sc);
1381    if (cs_cs89x0_probe(sc, &irq, &drq, iobase, unit, flags) == 0
1382	|| cs_attach(sc, unit, flags) == 0) {
1383	    free(sc, M_DEVBUF);
1384    } else {
1385	if ((irq != dev->id_irq)
1386	    || (drq != dev->id_drq)
1387	    || (iobase != dev->id_iobase)
1388	    || (unit != dev->id_unit)
1389	    || (flags != dev->id_flags)
1390		) {
1391		printf("failed to pnp card parametars\n");
1392	}
1393    }
1394    csintr_pnp_add(sc, dev->id_unit);
1395}
1396#endif /* NPNP */
1397