xref: /inferno-os/os/cerf1110/ether8900.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth /*
2*74a4d8c2SCharles.Forsyth  * Crystal CS8900 ethernet controller
3*74a4d8c2SCharles.Forsyth  *
4*74a4d8c2SCharles.Forsyth  * Todo:
5*74a4d8c2SCharles.Forsyth  * - promiscuous
6*74a4d8c2SCharles.Forsyth  *
7*74a4d8c2SCharles.Forsyth  * Copyright © 1998 Vita Nuova Limited.  All rights reserved.
8*74a4d8c2SCharles.Forsyth  * Revisions Copyright © 2000,2003 Vita Nuova Holdings Limited.  All rights reserved.
9*74a4d8c2SCharles.Forsyth  */
10*74a4d8c2SCharles.Forsyth 
11*74a4d8c2SCharles.Forsyth #include "u.h"
12*74a4d8c2SCharles.Forsyth #include "../port/lib.h"
13*74a4d8c2SCharles.Forsyth #include "mem.h"
14*74a4d8c2SCharles.Forsyth #include "dat.h"
15*74a4d8c2SCharles.Forsyth #include "fns.h"
16*74a4d8c2SCharles.Forsyth #include "io.h"
17*74a4d8c2SCharles.Forsyth #include "../port/netif.h"
18*74a4d8c2SCharles.Forsyth 
19*74a4d8c2SCharles.Forsyth #include "etherif.h"
20*74a4d8c2SCharles.Forsyth 
21*74a4d8c2SCharles.Forsyth typedef struct Ctlr Ctlr;
22*74a4d8c2SCharles.Forsyth 
23*74a4d8c2SCharles.Forsyth /*
24*74a4d8c2SCharles.Forsyth  * The CS8900 can be addressed from either  ISA I/O space
25*74a4d8c2SCharles.Forsyth  * or ISA memory space at the following virtual addresses,
26*74a4d8c2SCharles.Forsyth  * depending on the hardware's wiring.  MEMORY controls
27*74a4d8c2SCharles.Forsyth  * use of memory space.
28*74a4d8c2SCharles.Forsyth  * The cs8900 address pins are shifted by 1 relative to the CPU.
29*74a4d8c2SCharles.Forsyth  */
30*74a4d8c2SCharles.Forsyth enum {//18000000
31*74a4d8c2SCharles.Forsyth 	IsaIOBase		= 0x08000000,
32*74a4d8c2SCharles.Forsyth 	IsaMemBase	= 0xe0000000,
33*74a4d8c2SCharles.Forsyth 
34*74a4d8c2SCharles.Forsyth 	IOBase		= 0x300,
35*74a4d8c2SCharles.Forsyth 	MemBase		= 0xc0000,
36*74a4d8c2SCharles.Forsyth 
37*74a4d8c2SCharles.Forsyth 	MEMORY = 0,		/* set non-zero if memory mode to be used */
38*74a4d8c2SCharles.Forsyth 	DORESET = 1,		/* send soft-reset during initialisation */
39*74a4d8c2SCharles.Forsyth 	DEBUG = 0,
40*74a4d8c2SCharles.Forsyth };
41*74a4d8c2SCharles.Forsyth 
42*74a4d8c2SCharles.Forsyth #define	IOSHIFT	0	/* was 2 */
43*74a4d8c2SCharles.Forsyth #define	IOREG(r) (IsaIOBase+((IOBase+(r))<<IOSHIFT))
44*74a4d8c2SCharles.Forsyth 
45*74a4d8c2SCharles.Forsyth /* I/O accesses */
46*74a4d8c2SCharles.Forsyth #define	out16(port, val)	(*((ushort *)IOREG(port)) = (val))
47*74a4d8c2SCharles.Forsyth #define	in16(port)			*((ushort *)IOREG(port))
48*74a4d8c2SCharles.Forsyth #define	in8(port)			*((uchar *)IOREG(port))
49*74a4d8c2SCharles.Forsyth #define	regIOw(reg, val)	 do {out16(PpPtr, (reg)|0x3000); out16(PpData, val);} while(0)
50*74a4d8c2SCharles.Forsyth #define	regIOr(reg)		(out16(PpPtr, (reg)|0x3000), in16(PpData))
51*74a4d8c2SCharles.Forsyth #define	regIOr1(reg)		(out16(PpPtr, (reg)|0x3000), in16(PpData1))
52*74a4d8c2SCharles.Forsyth 
53*74a4d8c2SCharles.Forsyth /* Memory accesses */
54*74a4d8c2SCharles.Forsyth 
55*74a4d8c2SCharles.Forsyth #define	REGW(reg, val)		*((ushort *)IsaMemBase + MemBase + (reg)) = (val)
56*74a4d8c2SCharles.Forsyth #define	REGR(reg)			*((ushort *)IsaMemBase + MemBase + (reg))
57*74a4d8c2SCharles.Forsyth 
58*74a4d8c2SCharles.Forsyth enum {					/* I/O Mode Register Offsets */
59*74a4d8c2SCharles.Forsyth 	RxTxData	= 0x00,		/* receive/transmit data - port 0 */
60*74a4d8c2SCharles.Forsyth 	RxTxData1 = 0x02,		/* r/t data port 1 */
61*74a4d8c2SCharles.Forsyth 	TxCmdIO = 0x04,		/* transmit command */
62*74a4d8c2SCharles.Forsyth 	TxLenIO	= 0x06,		/* transmit length */
63*74a4d8c2SCharles.Forsyth 	IsqIO	= 0x08,		/* Interrupt status queue */
64*74a4d8c2SCharles.Forsyth 	PpPtr	= 0x0a,		/* packet page pointer */
65*74a4d8c2SCharles.Forsyth 	PpData	= 0x0c,		/* packet page data */
66*74a4d8c2SCharles.Forsyth 	PpData1	= 0x0e,		/* packet page data - port 1*/
67*74a4d8c2SCharles.Forsyth };
68*74a4d8c2SCharles.Forsyth 
69*74a4d8c2SCharles.Forsyth enum {					/* Memory Mode Register Offsets */
70*74a4d8c2SCharles.Forsyth 	/* Bus Interface Registers */
71*74a4d8c2SCharles.Forsyth 	Ern		= 0x0000,		/* EISA registration numberion */
72*74a4d8c2SCharles.Forsyth 	Pic		= 0x0002,		/* Product identification code */
73*74a4d8c2SCharles.Forsyth 	Iob		= 0x0020,		/* I/O base address */
74*74a4d8c2SCharles.Forsyth 	Intr		= 0x0022,		/* interrupt number */
75*74a4d8c2SCharles.Forsyth 	Mba		= 0x002c,		/* memory base address */
76*74a4d8c2SCharles.Forsyth 
77*74a4d8c2SCharles.Forsyth 	Ecr		= 0x0040,		/* EEPROM command register */
78*74a4d8c2SCharles.Forsyth 	Edw		= 0x0042,		/* EEPROM data word */
79*74a4d8c2SCharles.Forsyth 	Rbc		= 0x0050,		/* receive frame byte counter */
80*74a4d8c2SCharles.Forsyth 
81*74a4d8c2SCharles.Forsyth 	/* Status and Control Registers */
82*74a4d8c2SCharles.Forsyth 	RxCfg	= 0x0102,
83*74a4d8c2SCharles.Forsyth 	RxCtl	= 0x0104,
84*74a4d8c2SCharles.Forsyth 	TxCfg	= 0x0106,
85*74a4d8c2SCharles.Forsyth 	BufCfg	= 0x010a,
86*74a4d8c2SCharles.Forsyth 	LineCtl	= 0x0112,
87*74a4d8c2SCharles.Forsyth 	SelfCtl	= 0x0114,
88*74a4d8c2SCharles.Forsyth 	BusCtl	= 0x0116,
89*74a4d8c2SCharles.Forsyth 	TestCtl	= 0x0118,
90*74a4d8c2SCharles.Forsyth 	Isq		= 0x0120,
91*74a4d8c2SCharles.Forsyth 	RxEvent	= 0x0124,
92*74a4d8c2SCharles.Forsyth 	TxEvent	= 0x0128,
93*74a4d8c2SCharles.Forsyth 	BufEvent	= 0x012c,
94*74a4d8c2SCharles.Forsyth 	RxMISS	= 0x0130,
95*74a4d8c2SCharles.Forsyth 	TxCol	= 0x0132,
96*74a4d8c2SCharles.Forsyth 	LineSt	= 0x0134,
97*74a4d8c2SCharles.Forsyth 	SelfSt	= 0x0136,
98*74a4d8c2SCharles.Forsyth 	BusSt	= 0x0138,
99*74a4d8c2SCharles.Forsyth 	Tdr		= 0x013c,
100*74a4d8c2SCharles.Forsyth 
101*74a4d8c2SCharles.Forsyth 	/* Initiate Transmit Registers */
102*74a4d8c2SCharles.Forsyth 	TxCmd	= 0x0144,		/* transmit command */
103*74a4d8c2SCharles.Forsyth 	TxLen	= 0x0146,		/* transmit length */
104*74a4d8c2SCharles.Forsyth 
105*74a4d8c2SCharles.Forsyth 	/* Address Filter Registers */
106*74a4d8c2SCharles.Forsyth 	IndAddr	= 0x0158,		/* individual address registers */
107*74a4d8c2SCharles.Forsyth 
108*74a4d8c2SCharles.Forsyth 	/* Frame Location */
109*74a4d8c2SCharles.Forsyth 	RxStatus	= 0x0400,		/* receive status */
110*74a4d8c2SCharles.Forsyth 	RxLen	= 0x0402,		/* receive length */
111*74a4d8c2SCharles.Forsyth 	RxFrame	= 0x0404,		/* receive frame location */
112*74a4d8c2SCharles.Forsyth 	TxFrame	= 0x0a00,		/* transmit frame location */
113*74a4d8c2SCharles.Forsyth };
114*74a4d8c2SCharles.Forsyth 
115*74a4d8c2SCharles.Forsyth enum {					/* Ecr */
116*74a4d8c2SCharles.Forsyth 	Addr			= 0x00ff,		/* EEPROM word address (field) */
117*74a4d8c2SCharles.Forsyth 	Opcode		= 0x0300,		/* command opcode (field) */
118*74a4d8c2SCharles.Forsyth 		EEread	= 0x0200,
119*74a4d8c2SCharles.Forsyth 		EEwrite	= 0x0100,
120*74a4d8c2SCharles.Forsyth };
121*74a4d8c2SCharles.Forsyth 
122*74a4d8c2SCharles.Forsyth enum {					/* Isq */
123*74a4d8c2SCharles.Forsyth 	Regnum		= 0x003f,		/* register number held by Isq (field) */
124*74a4d8c2SCharles.Forsyth 		IsqRxEvent	= 0x04,
125*74a4d8c2SCharles.Forsyth 		IsqTxEvent	= 0x08,
126*74a4d8c2SCharles.Forsyth 		IsqBufEvent	= 0x0c,
127*74a4d8c2SCharles.Forsyth 		IsqRxMiss		= 0x10,
128*74a4d8c2SCharles.Forsyth 		IsqTxCol		= 0x12,
129*74a4d8c2SCharles.Forsyth 	RegContent 	= 0xffc0,		/* register data contents (field) */
130*74a4d8c2SCharles.Forsyth };
131*74a4d8c2SCharles.Forsyth 
132*74a4d8c2SCharles.Forsyth enum {					/* RxCfg */
133*74a4d8c2SCharles.Forsyth 	Skip_1		= 0x0040,
134*74a4d8c2SCharles.Forsyth 	StreamE		= 0x0080,
135*74a4d8c2SCharles.Forsyth 	RxOKiE		= 0x0100,
136*74a4d8c2SCharles.Forsyth 	RxDMAonly	= 0x0200,
137*74a4d8c2SCharles.Forsyth 	AutoRxDMAE	= 0x0400,
138*74a4d8c2SCharles.Forsyth 	BufferCRC		= 0x0800,
139*74a4d8c2SCharles.Forsyth 	CRCerroriE	= 0x1000,
140*74a4d8c2SCharles.Forsyth 	RuntiE		= 0x2000,
141*74a4d8c2SCharles.Forsyth 	ExtradataiE	= 0x4000,
142*74a4d8c2SCharles.Forsyth };
143*74a4d8c2SCharles.Forsyth 
144*74a4d8c2SCharles.Forsyth enum {					/* RxEvent */
145*74a4d8c2SCharles.Forsyth 	IAHash		= 0x0040,
146*74a4d8c2SCharles.Forsyth 	Dribblebits	= 0x0080,
147*74a4d8c2SCharles.Forsyth 	RxOK		= 0x0100,
148*74a4d8c2SCharles.Forsyth 	Hashed		= 0x0200,
149*74a4d8c2SCharles.Forsyth 	IndividualAdr	= 0x0400,
150*74a4d8c2SCharles.Forsyth 	Broadcast		= 0x0800,
151*74a4d8c2SCharles.Forsyth 	CRCerror		= 0x1000,
152*74a4d8c2SCharles.Forsyth 	Runt			= 0x2000,
153*74a4d8c2SCharles.Forsyth 	Extradata		= 0x4000,
154*74a4d8c2SCharles.Forsyth };
155*74a4d8c2SCharles.Forsyth 
156*74a4d8c2SCharles.Forsyth enum {					/* RxCtl */
157*74a4d8c2SCharles.Forsyth 	IAHashA		= 0x0040,
158*74a4d8c2SCharles.Forsyth 	PromiscuousA	= 0x0080,
159*74a4d8c2SCharles.Forsyth 	RxOKA		= 0x0100,
160*74a4d8c2SCharles.Forsyth 	MulticastA	= 0x0200,
161*74a4d8c2SCharles.Forsyth 	IndividualA	= 0x0400,
162*74a4d8c2SCharles.Forsyth 	BroadcastA	= 0x0800,
163*74a4d8c2SCharles.Forsyth 	CRCerrorA	= 0x1000,
164*74a4d8c2SCharles.Forsyth 	RuntA		= 0x2000,
165*74a4d8c2SCharles.Forsyth 	ExtradataA	= 0x4000,
166*74a4d8c2SCharles.Forsyth };
167*74a4d8c2SCharles.Forsyth 
168*74a4d8c2SCharles.Forsyth enum {					/* TxCfg */
169*74a4d8c2SCharles.Forsyth 	LossofCRSiE	= 0x0040,
170*74a4d8c2SCharles.Forsyth 	SQEerroriE	= 0x0080,
171*74a4d8c2SCharles.Forsyth 	TxOKiE		= 0x0100,
172*74a4d8c2SCharles.Forsyth 	OutofWindowiE	= 0x0200,
173*74a4d8c2SCharles.Forsyth 	JabberiE		= 0x0400,
174*74a4d8c2SCharles.Forsyth 	AnycolliE		= 0x0800,
175*74a4d8c2SCharles.Forsyth 	Coll16iE		= 0x8000,
176*74a4d8c2SCharles.Forsyth };
177*74a4d8c2SCharles.Forsyth 
178*74a4d8c2SCharles.Forsyth enum {					/* TxEvent */
179*74a4d8c2SCharles.Forsyth 	LossofCRS	= 0x0040,
180*74a4d8c2SCharles.Forsyth 	SQEerror		= 0x0080,
181*74a4d8c2SCharles.Forsyth 	TxOK		= 0x0100,
182*74a4d8c2SCharles.Forsyth 	OutofWindow	= 0x0200,
183*74a4d8c2SCharles.Forsyth 	Jabber		= 0x0400,
184*74a4d8c2SCharles.Forsyth 	NTxCols		= 0x7800,		/* number of Tx collisions (field) */
185*74a4d8c2SCharles.Forsyth 	coll16		= 0x8000,
186*74a4d8c2SCharles.Forsyth };
187*74a4d8c2SCharles.Forsyth 
188*74a4d8c2SCharles.Forsyth enum {					/* BufCfg */
189*74a4d8c2SCharles.Forsyth 	SWintX		= 0x0040,
190*74a4d8c2SCharles.Forsyth 	RxDMAiE		= 0x0080,
191*74a4d8c2SCharles.Forsyth 	Rdy4TxiE		= 0x0100,
192*74a4d8c2SCharles.Forsyth 	TxUnderruniE	= 0x0200,
193*74a4d8c2SCharles.Forsyth 	RxMissiE		= 0x0400,
194*74a4d8c2SCharles.Forsyth 	Rx128iE		= 0x0800,
195*74a4d8c2SCharles.Forsyth 	TxColOvfiE	= 0x1000,
196*74a4d8c2SCharles.Forsyth 	MissOvfloiE	= 0x2000,
197*74a4d8c2SCharles.Forsyth 	RxDestiE		= 0x8000,
198*74a4d8c2SCharles.Forsyth };
199*74a4d8c2SCharles.Forsyth 
200*74a4d8c2SCharles.Forsyth enum {					/* BufEvent */
201*74a4d8c2SCharles.Forsyth 	SWint		= 0x0040,
202*74a4d8c2SCharles.Forsyth 	RxDMAFrame	= 0x0080,
203*74a4d8c2SCharles.Forsyth 	Rdy4Tx		= 0x0100,
204*74a4d8c2SCharles.Forsyth 	TxUnderrun	= 0x0200,
205*74a4d8c2SCharles.Forsyth 	RxMiss		= 0x0400,
206*74a4d8c2SCharles.Forsyth 	Rx128		= 0x0800,
207*74a4d8c2SCharles.Forsyth 	RxDest		= 0x8000,
208*74a4d8c2SCharles.Forsyth };
209*74a4d8c2SCharles.Forsyth 
210*74a4d8c2SCharles.Forsyth enum {					/* RxMiss */
211*74a4d8c2SCharles.Forsyth 	MissCount	= 0xffc0,
212*74a4d8c2SCharles.Forsyth };
213*74a4d8c2SCharles.Forsyth 
214*74a4d8c2SCharles.Forsyth enum {					/* TxCol */
215*74a4d8c2SCharles.Forsyth 	ColCount	= 0xffc0,
216*74a4d8c2SCharles.Forsyth };
217*74a4d8c2SCharles.Forsyth 
218*74a4d8c2SCharles.Forsyth enum {					/* LineCtl */
219*74a4d8c2SCharles.Forsyth 	SerRxOn		= 0x0040,
220*74a4d8c2SCharles.Forsyth 	SerTxOn		= 0x0080,
221*74a4d8c2SCharles.Forsyth 	Iface			= 0x0300,		/* (field) 01 - AUI, 00 - 10BASE-T, 10 - Auto select */
222*74a4d8c2SCharles.Forsyth 	ModBackoffE	= 0x0800,
223*74a4d8c2SCharles.Forsyth 	PolarityDis	= 0x1000,
224*74a4d8c2SCharles.Forsyth 	DefDis		= 0x2000,
225*74a4d8c2SCharles.Forsyth 	LoRxSquelch	= 0x4000,
226*74a4d8c2SCharles.Forsyth };
227*74a4d8c2SCharles.Forsyth 
228*74a4d8c2SCharles.Forsyth enum {					/* LineSt */
229*74a4d8c2SCharles.Forsyth 	LinkOK		= 0x0080,
230*74a4d8c2SCharles.Forsyth 	AUI			= 0x0100,
231*74a4d8c2SCharles.Forsyth 	TenBT		= 0x0200,
232*74a4d8c2SCharles.Forsyth 	PolarityOK	= 0x1000,
233*74a4d8c2SCharles.Forsyth 	CRS			= 0x4000,
234*74a4d8c2SCharles.Forsyth };
235*74a4d8c2SCharles.Forsyth 
236*74a4d8c2SCharles.Forsyth enum {					/* SelfCtl */
237*74a4d8c2SCharles.Forsyth 	RESET		= 0x0040,
238*74a4d8c2SCharles.Forsyth 	SWSuspend	= 0x0100,
239*74a4d8c2SCharles.Forsyth 	HWSleepE		= 0x0200,
240*74a4d8c2SCharles.Forsyth 	HWStandbyE	= 0x0400,
241*74a4d8c2SCharles.Forsyth };
242*74a4d8c2SCharles.Forsyth 
243*74a4d8c2SCharles.Forsyth enum {					/* SelfSt */
244*74a4d8c2SCharles.Forsyth 	Active3V		= 0x0040,
245*74a4d8c2SCharles.Forsyth 	INITD		= 0x0080,
246*74a4d8c2SCharles.Forsyth 	SIBUSY		= 0x0100,
247*74a4d8c2SCharles.Forsyth 	EepromPresent	= 0x0200,
248*74a4d8c2SCharles.Forsyth 	EepromOK	= 0x0400,
249*74a4d8c2SCharles.Forsyth 	ElPresent		= 0x0800,
250*74a4d8c2SCharles.Forsyth 	EeSize		= 0x1000,
251*74a4d8c2SCharles.Forsyth };
252*74a4d8c2SCharles.Forsyth 
253*74a4d8c2SCharles.Forsyth enum {					/* BusCtl */
254*74a4d8c2SCharles.Forsyth 	ResetRxDMA	= 0x0040,
255*74a4d8c2SCharles.Forsyth 	UseSA		= 0x0200,
256*74a4d8c2SCharles.Forsyth 	MemoryE		= 0x0400,
257*74a4d8c2SCharles.Forsyth 	DMABurst		= 0x0800,
258*74a4d8c2SCharles.Forsyth 	EnableIRQ		= 0x8000,
259*74a4d8c2SCharles.Forsyth };
260*74a4d8c2SCharles.Forsyth 
261*74a4d8c2SCharles.Forsyth enum {					/* BusST */
262*74a4d8c2SCharles.Forsyth 	TxBidErr		= 0x0080,
263*74a4d8c2SCharles.Forsyth 	Rdy4TxNOW	= 0x0100,
264*74a4d8c2SCharles.Forsyth };
265*74a4d8c2SCharles.Forsyth 
266*74a4d8c2SCharles.Forsyth enum {					/* TestCtl */
267*74a4d8c2SCharles.Forsyth 	FDX			= 0x4000,		/* full duplex */
268*74a4d8c2SCharles.Forsyth };
269*74a4d8c2SCharles.Forsyth 
270*74a4d8c2SCharles.Forsyth enum {					/* TxCmd */
271*74a4d8c2SCharles.Forsyth 	TxStart		= 0x00c0,		/* bytes before transmit starts (field) */
272*74a4d8c2SCharles.Forsyth 		TxSt5	= 0x0000,		/* start after 5 bytes */
273*74a4d8c2SCharles.Forsyth 		TxSt381	= 0x0040,		/* start after 381 bytes */
274*74a4d8c2SCharles.Forsyth 		TxSt1021	= 0x0080,		/* start after 1021 bytes */
275*74a4d8c2SCharles.Forsyth 		TxStAll	= 0x00c0,		/* start after the entire frame is in the cs8900 */
276*74a4d8c2SCharles.Forsyth 	Force		= 0x0100,
277*74a4d8c2SCharles.Forsyth 	Onecoll		= 0x0200,
278*74a4d8c2SCharles.Forsyth 	InhibitCRC	= 0x1000,
279*74a4d8c2SCharles.Forsyth 	TxPadDis		= 0x2000,
280*74a4d8c2SCharles.Forsyth };
281*74a4d8c2SCharles.Forsyth 
282*74a4d8c2SCharles.Forsyth enum {	/* EEPROM format */
283*74a4d8c2SCharles.Forsyth 	Edataoff	= 0x1C,	/* start of data (ether address) */
284*74a4d8c2SCharles.Forsyth 	Edatalen	= 0x14,	/* data count in 16-bit words */
285*74a4d8c2SCharles.Forsyth };
286*74a4d8c2SCharles.Forsyth 
287*74a4d8c2SCharles.Forsyth struct Ctlr {
288*74a4d8c2SCharles.Forsyth 	Lock;
289*74a4d8c2SCharles.Forsyth 	Block*	waiting;	/* waiting for space in FIFO */
290*74a4d8c2SCharles.Forsyth 	int	model;
291*74a4d8c2SCharles.Forsyth 	int	rev;
292*74a4d8c2SCharles.Forsyth 
293*74a4d8c2SCharles.Forsyth 	ulong	collisions;
294*74a4d8c2SCharles.Forsyth };
295*74a4d8c2SCharles.Forsyth 
296*74a4d8c2SCharles.Forsyth static void
regw(int reg,int val)297*74a4d8c2SCharles.Forsyth regw(int reg, int val)
298*74a4d8c2SCharles.Forsyth {
299*74a4d8c2SCharles.Forsyth 	if(DEBUG)
300*74a4d8c2SCharles.Forsyth 		print("r%4.4ux <- %4.4ux\n", reg, val);
301*74a4d8c2SCharles.Forsyth 	if(MEMORY){
302*74a4d8c2SCharles.Forsyth 		REGW(reg, val);
303*74a4d8c2SCharles.Forsyth 	}else{
304*74a4d8c2SCharles.Forsyth 		out16(PpPtr, reg);
305*74a4d8c2SCharles.Forsyth 		out16(PpData, val);
306*74a4d8c2SCharles.Forsyth 	}
307*74a4d8c2SCharles.Forsyth }
308*74a4d8c2SCharles.Forsyth 
309*74a4d8c2SCharles.Forsyth static int
regr(int reg)310*74a4d8c2SCharles.Forsyth regr(int reg)
311*74a4d8c2SCharles.Forsyth {
312*74a4d8c2SCharles.Forsyth 	int v;
313*74a4d8c2SCharles.Forsyth 
314*74a4d8c2SCharles.Forsyth 	if(MEMORY)
315*74a4d8c2SCharles.Forsyth 		return REGR(reg);
316*74a4d8c2SCharles.Forsyth 	out16(PpPtr, reg);
317*74a4d8c2SCharles.Forsyth 	v = in16(PpData);
318*74a4d8c2SCharles.Forsyth 	if(DEBUG)
319*74a4d8c2SCharles.Forsyth 		print("r%4.4ux = %4.4ux\n", reg, v);
320*74a4d8c2SCharles.Forsyth 	return v;
321*74a4d8c2SCharles.Forsyth }
322*74a4d8c2SCharles.Forsyth 
323*74a4d8c2SCharles.Forsyth /*
324*74a4d8c2SCharles.Forsyth  * copy frames in and out, accounting for shorts aligned as longs in IO memory
325*74a4d8c2SCharles.Forsyth  */
326*74a4d8c2SCharles.Forsyth 
327*74a4d8c2SCharles.Forsyth static void
copypktin(void * ad,int len)328*74a4d8c2SCharles.Forsyth copypktin(void *ad, int len)
329*74a4d8c2SCharles.Forsyth {
330*74a4d8c2SCharles.Forsyth 	ushort *s, *d;
331*74a4d8c2SCharles.Forsyth 	int ns;
332*74a4d8c2SCharles.Forsyth 
333*74a4d8c2SCharles.Forsyth 	if(!MEMORY){
334*74a4d8c2SCharles.Forsyth 		d = ad;
335*74a4d8c2SCharles.Forsyth 		/*
336*74a4d8c2SCharles.Forsyth 		 * contrary to data sheet DS271PP3 pages 77-78,
337*74a4d8c2SCharles.Forsyth 		 * the data is not preceded by status & length
338*74a4d8c2SCharles.Forsyth 		 * perhaps because it has been read directly.
339*74a4d8c2SCharles.Forsyth 		 */
340*74a4d8c2SCharles.Forsyth 		for(ns = len>>1; --ns >= 0;)
341*74a4d8c2SCharles.Forsyth 			*d++ = in16(RxTxData);
342*74a4d8c2SCharles.Forsyth 		if(len & 1)
343*74a4d8c2SCharles.Forsyth 			*(uchar*)d = in16(RxTxData);
344*74a4d8c2SCharles.Forsyth 		return;
345*74a4d8c2SCharles.Forsyth 	}
346*74a4d8c2SCharles.Forsyth 	d = ad;
347*74a4d8c2SCharles.Forsyth 	s = (ushort*)IsaMemBase + MemBase + RxFrame;
348*74a4d8c2SCharles.Forsyth 	for(ns = len>>1; --ns >= 0;){
349*74a4d8c2SCharles.Forsyth 		*d++ = *s;
350*74a4d8c2SCharles.Forsyth 		s += 2;
351*74a4d8c2SCharles.Forsyth 	}
352*74a4d8c2SCharles.Forsyth 	if(len & 1)
353*74a4d8c2SCharles.Forsyth 		*(uchar*)d = *s;
354*74a4d8c2SCharles.Forsyth }
355*74a4d8c2SCharles.Forsyth 
356*74a4d8c2SCharles.Forsyth static void
copypktout(void * as,int len)357*74a4d8c2SCharles.Forsyth copypktout(void *as, int len)
358*74a4d8c2SCharles.Forsyth {
359*74a4d8c2SCharles.Forsyth 	ushort *s, *d;
360*74a4d8c2SCharles.Forsyth 	int ns;
361*74a4d8c2SCharles.Forsyth 
362*74a4d8c2SCharles.Forsyth 	if(!MEMORY){
363*74a4d8c2SCharles.Forsyth 		s = as;
364*74a4d8c2SCharles.Forsyth 		ns = (len+1)>>1;
365*74a4d8c2SCharles.Forsyth 		while(--ns >= 0)
366*74a4d8c2SCharles.Forsyth 			out16(RxTxData, *s++);
367*74a4d8c2SCharles.Forsyth 		return;
368*74a4d8c2SCharles.Forsyth 	}
369*74a4d8c2SCharles.Forsyth 	s = as;
370*74a4d8c2SCharles.Forsyth 	d = (ushort*)IsaMemBase + MemBase + TxFrame;
371*74a4d8c2SCharles.Forsyth 	ns = (len+1)>>1;
372*74a4d8c2SCharles.Forsyth 	while(--ns >= 0){
373*74a4d8c2SCharles.Forsyth 		*d = *s++;
374*74a4d8c2SCharles.Forsyth 		d += 2;
375*74a4d8c2SCharles.Forsyth 	}
376*74a4d8c2SCharles.Forsyth }
377*74a4d8c2SCharles.Forsyth 
378*74a4d8c2SCharles.Forsyth static long
ifstat(Ether * ether,void * a,long n,ulong offset)379*74a4d8c2SCharles.Forsyth ifstat(Ether* ether, void* a, long n, ulong offset)
380*74a4d8c2SCharles.Forsyth {
381*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
382*74a4d8c2SCharles.Forsyth 	char *p;
383*74a4d8c2SCharles.Forsyth 	int len;
384*74a4d8c2SCharles.Forsyth 
385*74a4d8c2SCharles.Forsyth 	if(n == 0)
386*74a4d8c2SCharles.Forsyth 		return 0;
387*74a4d8c2SCharles.Forsyth 
388*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
389*74a4d8c2SCharles.Forsyth 	p = malloc(READSTR);
390*74a4d8c2SCharles.Forsyth 	len = snprint(p, READSTR, "Overflow: %ud\n", ether->overflows);
391*74a4d8c2SCharles.Forsyth 	len += snprint(p+len, READSTR-len, "CRC Error: %ud\n", ether->crcs);
392*74a4d8c2SCharles.Forsyth 	snprint(p+len, READSTR-len, "Collision Seen: %lud\n", ctlr->collisions);
393*74a4d8c2SCharles.Forsyth 
394*74a4d8c2SCharles.Forsyth 	n = readstr(offset, a, n, p);
395*74a4d8c2SCharles.Forsyth 	free(p);
396*74a4d8c2SCharles.Forsyth 
397*74a4d8c2SCharles.Forsyth 	return n;
398*74a4d8c2SCharles.Forsyth }
399*74a4d8c2SCharles.Forsyth 
400*74a4d8c2SCharles.Forsyth static void
promiscuous(void * arg,int on)401*74a4d8c2SCharles.Forsyth promiscuous(void* arg, int on)
402*74a4d8c2SCharles.Forsyth {
403*74a4d8c2SCharles.Forsyth 	USED(arg, on);
404*74a4d8c2SCharles.Forsyth }
405*74a4d8c2SCharles.Forsyth 
406*74a4d8c2SCharles.Forsyth static void
attach(Ether * ether)407*74a4d8c2SCharles.Forsyth attach(Ether *ether)
408*74a4d8c2SCharles.Forsyth {
409*74a4d8c2SCharles.Forsyth 	int reg;
410*74a4d8c2SCharles.Forsyth 
411*74a4d8c2SCharles.Forsyth 	USED(ether);
412*74a4d8c2SCharles.Forsyth 	/* enable transmit and receive */
413*74a4d8c2SCharles.Forsyth 	reg = regr(BusCtl);
414*74a4d8c2SCharles.Forsyth 	regw(BusCtl, reg|EnableIRQ);
415*74a4d8c2SCharles.Forsyth 	reg = regr(LineCtl);
416*74a4d8c2SCharles.Forsyth 	regw(LineCtl, reg|SerRxOn|SerTxOn);
417*74a4d8c2SCharles.Forsyth 	if(DEBUG){
418*74a4d8c2SCharles.Forsyth 		iprint("bus=%4.4ux line=%4.4ux\n", regr(BusCtl), regr(LineCtl));
419*74a4d8c2SCharles.Forsyth 		iprint("rc=%4.4ux tc=%4.4ux bc=%4.4ux\n", regr(RxCfg), regr(TxCfg), regr(BufCfg));
420*74a4d8c2SCharles.Forsyth 	}
421*74a4d8c2SCharles.Forsyth }
422*74a4d8c2SCharles.Forsyth 
423*74a4d8c2SCharles.Forsyth static void
txstart(Ether * ether,int dowait)424*74a4d8c2SCharles.Forsyth txstart(Ether *ether, int dowait)
425*74a4d8c2SCharles.Forsyth {
426*74a4d8c2SCharles.Forsyth 	int len, status;
427*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
428*74a4d8c2SCharles.Forsyth 	Block *b;
429*74a4d8c2SCharles.Forsyth 
430*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
431*74a4d8c2SCharles.Forsyth 	for(;;){
432*74a4d8c2SCharles.Forsyth 		if((b = ctlr->waiting) == nil){
433*74a4d8c2SCharles.Forsyth 			if((b = qget(ether->oq)) == nil)
434*74a4d8c2SCharles.Forsyth 				break;
435*74a4d8c2SCharles.Forsyth 		}else{
436*74a4d8c2SCharles.Forsyth 			if(!dowait)
437*74a4d8c2SCharles.Forsyth 				break;
438*74a4d8c2SCharles.Forsyth 			ctlr->waiting = nil;
439*74a4d8c2SCharles.Forsyth 		}
440*74a4d8c2SCharles.Forsyth 		len = BLEN(b);
441*74a4d8c2SCharles.Forsyth 		if(MEMORY){
442*74a4d8c2SCharles.Forsyth 			regw(TxCmd, TxSt381);
443*74a4d8c2SCharles.Forsyth 			regw(TxLen, len);
444*74a4d8c2SCharles.Forsyth 		}else{
445*74a4d8c2SCharles.Forsyth 			out16(TxCmdIO, TxStAll);
446*74a4d8c2SCharles.Forsyth 			out16(TxLenIO, len);
447*74a4d8c2SCharles.Forsyth 		}
448*74a4d8c2SCharles.Forsyth 		status = regr(BusSt);
449*74a4d8c2SCharles.Forsyth 		if((status & Rdy4TxNOW) == 0) {
450*74a4d8c2SCharles.Forsyth 			ctlr->waiting = b;
451*74a4d8c2SCharles.Forsyth 			break;
452*74a4d8c2SCharles.Forsyth 		}
453*74a4d8c2SCharles.Forsyth 		/*
454*74a4d8c2SCharles.Forsyth 		 * Copy the packet to the transmit buffer.
455*74a4d8c2SCharles.Forsyth 		 */
456*74a4d8c2SCharles.Forsyth 		copypktout(b->rp, len);
457*74a4d8c2SCharles.Forsyth 		freeb(b);
458*74a4d8c2SCharles.Forsyth 	}
459*74a4d8c2SCharles.Forsyth }
460*74a4d8c2SCharles.Forsyth 
461*74a4d8c2SCharles.Forsyth static void
transmit(Ether * ether)462*74a4d8c2SCharles.Forsyth transmit(Ether *ether)
463*74a4d8c2SCharles.Forsyth {
464*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
465*74a4d8c2SCharles.Forsyth 
466*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
467*74a4d8c2SCharles.Forsyth 	ilock(ctlr);
468*74a4d8c2SCharles.Forsyth 	txstart(ether, 0);
469*74a4d8c2SCharles.Forsyth 	iunlock(ctlr);
470*74a4d8c2SCharles.Forsyth }
471*74a4d8c2SCharles.Forsyth 
472*74a4d8c2SCharles.Forsyth static void
interrupt(Ureg *,void * arg)473*74a4d8c2SCharles.Forsyth interrupt(Ureg*, void *arg)
474*74a4d8c2SCharles.Forsyth {
475*74a4d8c2SCharles.Forsyth 	Ether *ether;
476*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
477*74a4d8c2SCharles.Forsyth 	int len, events, status;
478*74a4d8c2SCharles.Forsyth 	Block *b;
479*74a4d8c2SCharles.Forsyth 
480*74a4d8c2SCharles.Forsyth 	ether = arg;
481*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
482*74a4d8c2SCharles.Forsyth 	ilock(ctlr);
483*74a4d8c2SCharles.Forsyth 	while((events = (MEMORY?regr(Isq):in16(IsqIO))) != 0) {
484*74a4d8c2SCharles.Forsyth 		status = events&RegContent;
485*74a4d8c2SCharles.Forsyth 		if(DEBUG)
486*74a4d8c2SCharles.Forsyth 			iprint("status %4.4ux event %4.4ux\n", status, events);
487*74a4d8c2SCharles.Forsyth 		switch(events&Regnum) {
488*74a4d8c2SCharles.Forsyth 
489*74a4d8c2SCharles.Forsyth 		case IsqBufEvent:
490*74a4d8c2SCharles.Forsyth 			if(status&Rdy4Tx) {
491*74a4d8c2SCharles.Forsyth 				if((b = ctlr->waiting) != nil){
492*74a4d8c2SCharles.Forsyth 					ctlr->waiting = nil;
493*74a4d8c2SCharles.Forsyth 					copypktout(b->rp, BLEN(b));
494*74a4d8c2SCharles.Forsyth 					freeb(b);
495*74a4d8c2SCharles.Forsyth 					/* wait for IsqTxEvent to send remaining packets in txstart */
496*74a4d8c2SCharles.Forsyth 				}else
497*74a4d8c2SCharles.Forsyth 					txstart(ether, 0);
498*74a4d8c2SCharles.Forsyth 			}
499*74a4d8c2SCharles.Forsyth 			break;
500*74a4d8c2SCharles.Forsyth 
501*74a4d8c2SCharles.Forsyth 		case IsqRxEvent:
502*74a4d8c2SCharles.Forsyth 			if(status&RxOK) {
503*74a4d8c2SCharles.Forsyth 				len = regr(RxLen);
504*74a4d8c2SCharles.Forsyth 				if(DEBUG)
505*74a4d8c2SCharles.Forsyth 					iprint("rxlen=%d\n", len);
506*74a4d8c2SCharles.Forsyth 				if((b = iallocb(len)) != 0) {
507*74a4d8c2SCharles.Forsyth 					copypktin(b->wp, len);
508*74a4d8c2SCharles.Forsyth 					b->wp += len;
509*74a4d8c2SCharles.Forsyth 					etheriq(ether, b, 1);
510*74a4d8c2SCharles.Forsyth 				}
511*74a4d8c2SCharles.Forsyth 			}
512*74a4d8c2SCharles.Forsyth 			break;
513*74a4d8c2SCharles.Forsyth 
514*74a4d8c2SCharles.Forsyth 		case IsqTxEvent:
515*74a4d8c2SCharles.Forsyth 			if(status&TxOK)
516*74a4d8c2SCharles.Forsyth 				txstart(ether, 1);
517*74a4d8c2SCharles.Forsyth 			break;
518*74a4d8c2SCharles.Forsyth 
519*74a4d8c2SCharles.Forsyth 		case IsqRxMiss:
520*74a4d8c2SCharles.Forsyth 			ether->overflows++;
521*74a4d8c2SCharles.Forsyth 			break;
522*74a4d8c2SCharles.Forsyth 
523*74a4d8c2SCharles.Forsyth 		case IsqTxCol:
524*74a4d8c2SCharles.Forsyth 			ctlr->collisions++;
525*74a4d8c2SCharles.Forsyth 			break;
526*74a4d8c2SCharles.Forsyth 		}
527*74a4d8c2SCharles.Forsyth 	}
528*74a4d8c2SCharles.Forsyth 	iunlock(ctlr);
529*74a4d8c2SCharles.Forsyth }
530*74a4d8c2SCharles.Forsyth 
531*74a4d8c2SCharles.Forsyth static int
eepromwait(void)532*74a4d8c2SCharles.Forsyth eepromwait(void)
533*74a4d8c2SCharles.Forsyth {
534*74a4d8c2SCharles.Forsyth 	int i;
535*74a4d8c2SCharles.Forsyth 
536*74a4d8c2SCharles.Forsyth 	for(i=0; i<100000; i++)
537*74a4d8c2SCharles.Forsyth 		if((regIOr(SelfSt) & SIBUSY) == 0)
538*74a4d8c2SCharles.Forsyth 			return 0;
539*74a4d8c2SCharles.Forsyth 	return -1;
540*74a4d8c2SCharles.Forsyth }
541*74a4d8c2SCharles.Forsyth 
542*74a4d8c2SCharles.Forsyth static int
eepromrd(void * buf,int off,int n)543*74a4d8c2SCharles.Forsyth eepromrd(void *buf, int off, int n)
544*74a4d8c2SCharles.Forsyth {
545*74a4d8c2SCharles.Forsyth 	int i;
546*74a4d8c2SCharles.Forsyth 	ushort *p;
547*74a4d8c2SCharles.Forsyth 
548*74a4d8c2SCharles.Forsyth 	p = buf;
549*74a4d8c2SCharles.Forsyth 	n /= 2;
550*74a4d8c2SCharles.Forsyth 	for(i=0; i<n; i++){
551*74a4d8c2SCharles.Forsyth 		if(eepromwait() < 0)
552*74a4d8c2SCharles.Forsyth 			return -1;
553*74a4d8c2SCharles.Forsyth 		regIOw(Ecr, EEread | (off+i));
554*74a4d8c2SCharles.Forsyth 		if(eepromwait() < 0)
555*74a4d8c2SCharles.Forsyth 			return -1;
556*74a4d8c2SCharles.Forsyth 		p[i] = regIOr(Edw);
557*74a4d8c2SCharles.Forsyth 	}
558*74a4d8c2SCharles.Forsyth 	return 0;
559*74a4d8c2SCharles.Forsyth }
560*74a4d8c2SCharles.Forsyth 
561*74a4d8c2SCharles.Forsyth static int
reset(Ether * ether)562*74a4d8c2SCharles.Forsyth reset(Ether* ether)
563*74a4d8c2SCharles.Forsyth {
564*74a4d8c2SCharles.Forsyth 	int i, reg, easet;
565*74a4d8c2SCharles.Forsyth 	uchar ea[Eaddrlen];
566*74a4d8c2SCharles.Forsyth 	ushort buf[Edatalen];
567*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
568*74a4d8c2SCharles.Forsyth 
569*74a4d8c2SCharles.Forsyth 	if(!MEMORY)
570*74a4d8c2SCharles.Forsyth 		mmuphysmap(IsaIOBase, 64*1024);
571*74a4d8c2SCharles.Forsyth 
572*74a4d8c2SCharles.Forsyth 	delay(120);	/* allow time for chip to reset */
573*74a4d8c2SCharles.Forsyth 
574*74a4d8c2SCharles.Forsyth 	if(0){
575*74a4d8c2SCharles.Forsyth 		*(ushort*)IsaIOBase = 0xDEAD;	/* force rubbish on bus */
576*74a4d8c2SCharles.Forsyth 		for(i=0; i<100; i++){
577*74a4d8c2SCharles.Forsyth 			if(in16(PpPtr) == 0x3000)
578*74a4d8c2SCharles.Forsyth 				break;
579*74a4d8c2SCharles.Forsyth 			delay(1);
580*74a4d8c2SCharles.Forsyth 		}
581*74a4d8c2SCharles.Forsyth 		if(i>=100){
582*74a4d8c2SCharles.Forsyth 			iprint("failed init: reg(0xA): %4.4ux, should be 0x3000\n", in16(PpPtr));
583*74a4d8c2SCharles.Forsyth 			return -1;
584*74a4d8c2SCharles.Forsyth 		}
585*74a4d8c2SCharles.Forsyth 	}
586*74a4d8c2SCharles.Forsyth iprint("8900: %4.4ux (selfst) %4.4ux (linest)\n", regIOr(SelfSt), regIOr(LineSt));
587*74a4d8c2SCharles.Forsyth iprint("8900: %4.4ux %4.4ux\n", regIOr(Ern), regIOr(Pic));
588*74a4d8c2SCharles.Forsyth 
589*74a4d8c2SCharles.Forsyth 	/*
590*74a4d8c2SCharles.Forsyth 	 * Identify the chip by reading the Pic register.
591*74a4d8c2SCharles.Forsyth 	 * The EISA registration number is in the low word
592*74a4d8c2SCharles.Forsyth 	 * and the product identification code in the high code.
593*74a4d8c2SCharles.Forsyth 	 * The ERN for Crystal Semiconductor is 0x630e.
594*74a4d8c2SCharles.Forsyth 	 * Bits 0-7 and 13-15 of the Pic should be zero for a CS8900.
595*74a4d8c2SCharles.Forsyth 	 */
596*74a4d8c2SCharles.Forsyth 	if(regIOr(Ern) != 0x630e || (regIOr(Pic) & 0xe0ff) != 0)
597*74a4d8c2SCharles.Forsyth 		return -1;
598*74a4d8c2SCharles.Forsyth 
599*74a4d8c2SCharles.Forsyth 	if(ether->ctlr == nil)
600*74a4d8c2SCharles.Forsyth 		ether->ctlr = malloc(sizeof(Ctlr));
601*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
602*74a4d8c2SCharles.Forsyth 
603*74a4d8c2SCharles.Forsyth 	reg = regIOr(Pic);
604*74a4d8c2SCharles.Forsyth 	ctlr->model = reg>>14;
605*74a4d8c2SCharles.Forsyth 	ctlr->rev = (reg >> 8) & 0x1F;
606*74a4d8c2SCharles.Forsyth 
607*74a4d8c2SCharles.Forsyth 	ether->mbps = 10;
608*74a4d8c2SCharles.Forsyth 
609*74a4d8c2SCharles.Forsyth 	memset(ea, 0, Eaddrlen);
610*74a4d8c2SCharles.Forsyth 	easet = memcmp(ea, ether->ea, Eaddrlen);
611*74a4d8c2SCharles.Forsyth 	memset(buf, 0, sizeof(buf));
612*74a4d8c2SCharles.Forsyth 	if(regIOr(SelfSt) & EepromPresent) {	/* worth a look */
613*74a4d8c2SCharles.Forsyth 		if(eepromrd(buf, Edataoff, sizeof(buf)) >= 0){
614*74a4d8c2SCharles.Forsyth 			for(i=0; i<3; i++){
615*74a4d8c2SCharles.Forsyth 				ether->ea[2*i] = buf[i];
616*74a4d8c2SCharles.Forsyth 				ether->ea[2*i+1] = buf[i] >> 8;
617*74a4d8c2SCharles.Forsyth 			}
618*74a4d8c2SCharles.Forsyth 			easet = 1;
619*74a4d8c2SCharles.Forsyth 		}else
620*74a4d8c2SCharles.Forsyth 			iprint("cs8900: can't read EEPROM\n");
621*74a4d8c2SCharles.Forsyth 	}
622*74a4d8c2SCharles.Forsyth 	if(!easet){
623*74a4d8c2SCharles.Forsyth 		iprint("cs8900: ethernet address not configured\n");
624*74a4d8c2SCharles.Forsyth 		return -1;
625*74a4d8c2SCharles.Forsyth 	}
626*74a4d8c2SCharles.Forsyth 	memmove(ea, ether->ea, Eaddrlen);
627*74a4d8c2SCharles.Forsyth 
628*74a4d8c2SCharles.Forsyth 	if(DORESET){
629*74a4d8c2SCharles.Forsyth 		/*
630*74a4d8c2SCharles.Forsyth 		 * Reset the chip and ensure 16-bit mode operation
631*74a4d8c2SCharles.Forsyth 		 */
632*74a4d8c2SCharles.Forsyth 		regIOw(SelfCtl, RESET);
633*74a4d8c2SCharles.Forsyth 		delay(10);
634*74a4d8c2SCharles.Forsyth 		i=in8(PpPtr); 	USED(i);
635*74a4d8c2SCharles.Forsyth 		i=in8(PpPtr+1); USED(i);
636*74a4d8c2SCharles.Forsyth 		i=in8(PpPtr); 	USED(i);
637*74a4d8c2SCharles.Forsyth 		i=in8(PpPtr+1);	USED(i);
638*74a4d8c2SCharles.Forsyth 
639*74a4d8c2SCharles.Forsyth 		/*
640*74a4d8c2SCharles.Forsyth 		 * Wait for initialisation and EEPROM reads to complete
641*74a4d8c2SCharles.Forsyth 		 */
642*74a4d8c2SCharles.Forsyth 		i=0;
643*74a4d8c2SCharles.Forsyth 		for(;;) {
644*74a4d8c2SCharles.Forsyth 			short st = regIOr(SelfSt);
645*74a4d8c2SCharles.Forsyth 			if((st&SIBUSY) == 0 && st&INITD)
646*74a4d8c2SCharles.Forsyth 				break;
647*74a4d8c2SCharles.Forsyth 			if(i++ > 1000000)
648*74a4d8c2SCharles.Forsyth 				panic("cs8900: initialisation failed");
649*74a4d8c2SCharles.Forsyth 		}
650*74a4d8c2SCharles.Forsyth 	}
651*74a4d8c2SCharles.Forsyth 
652*74a4d8c2SCharles.Forsyth 	if(MEMORY){
653*74a4d8c2SCharles.Forsyth 		/*
654*74a4d8c2SCharles.Forsyth 		 * Enable memory mode operation.
655*74a4d8c2SCharles.Forsyth 		 */
656*74a4d8c2SCharles.Forsyth 		regIOw(Mba, MemBase & 0xffff);
657*74a4d8c2SCharles.Forsyth 		regIOw(Mba+2, MemBase >> 16);
658*74a4d8c2SCharles.Forsyth 		regIOw(BusCtl, MemoryE|UseSA);
659*74a4d8c2SCharles.Forsyth 	}
660*74a4d8c2SCharles.Forsyth 
661*74a4d8c2SCharles.Forsyth 	/*
662*74a4d8c2SCharles.Forsyth 	 * Enable 10BASE-T half duplex, transmit in interrupt mode
663*74a4d8c2SCharles.Forsyth 	 */
664*74a4d8c2SCharles.Forsyth 	reg = regr(LineCtl);
665*74a4d8c2SCharles.Forsyth 	regw(LineCtl, reg&~Iface);
666*74a4d8c2SCharles.Forsyth 	reg = regr(TestCtl);
667*74a4d8c2SCharles.Forsyth 	if(ether->fullduplex)
668*74a4d8c2SCharles.Forsyth 		regw(TestCtl, reg|FDX);
669*74a4d8c2SCharles.Forsyth 	else
670*74a4d8c2SCharles.Forsyth 		regw(TestCtl, reg&~FDX);
671*74a4d8c2SCharles.Forsyth 	regw(BufCfg, Rdy4TxiE|TxUnderruniE);
672*74a4d8c2SCharles.Forsyth 	regw(TxCfg, TxOKiE|AnycolliE|LossofCRSiE|Coll16iE);
673*74a4d8c2SCharles.Forsyth 	regw(RxCfg, RxOKiE|CRCerroriE|RuntiE|ExtradataiE);
674*74a4d8c2SCharles.Forsyth 	regw(RxCtl, RxOKA|IndividualA|BroadcastA);
675*74a4d8c2SCharles.Forsyth 
676*74a4d8c2SCharles.Forsyth 	for(i=0; i<Eaddrlen; i+=2)
677*74a4d8c2SCharles.Forsyth 		regw(IndAddr+i, ea[i] | (ea[i+1] << 8));
678*74a4d8c2SCharles.Forsyth 
679*74a4d8c2SCharles.Forsyth 	/* IRQ tied to INTRQ0 */
680*74a4d8c2SCharles.Forsyth 	regw(Intr, 0);
681*74a4d8c2SCharles.Forsyth 
682*74a4d8c2SCharles.Forsyth 	/*
683*74a4d8c2SCharles.Forsyth 	 * Linkage to the generic ethernet driver.
684*74a4d8c2SCharles.Forsyth 	 */
685*74a4d8c2SCharles.Forsyth 	ether->attach = attach;
686*74a4d8c2SCharles.Forsyth 	ether->transmit = transmit;
687*74a4d8c2SCharles.Forsyth 	ether->interrupt = interrupt;
688*74a4d8c2SCharles.Forsyth 	ether->ifstat = ifstat;
689*74a4d8c2SCharles.Forsyth 
690*74a4d8c2SCharles.Forsyth 	ether->arg = ether;
691*74a4d8c2SCharles.Forsyth 	ether->promiscuous = promiscuous;
692*74a4d8c2SCharles.Forsyth 
693*74a4d8c2SCharles.Forsyth 	ether->itype = BusGPIOrising;	/* TO DO: this shouldn't be done here */
694*74a4d8c2SCharles.Forsyth 
695*74a4d8c2SCharles.Forsyth 	return 0;
696*74a4d8c2SCharles.Forsyth }
697*74a4d8c2SCharles.Forsyth 
698*74a4d8c2SCharles.Forsyth void
ether8900link(void)699*74a4d8c2SCharles.Forsyth ether8900link(void)
700*74a4d8c2SCharles.Forsyth {
701*74a4d8c2SCharles.Forsyth 	addethercard("CS8900",  reset);
702*74a4d8c2SCharles.Forsyth }
703