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