FreeBSD/Linux Kernel Cross Reference
sys/pc/ether589.c
1 /*
2 * 3C589 and 3C562.
3 * To do:
4 * check xcvr10Base2 still works (is GlobalReset necessary?).
5 */
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "../port/error.h"
13 #include "../port/netif.h"
14
15 #include "etherif.h"
16
17 enum { /* all windows */
18 CommandR = 0x000E,
19 IntStatusR = 0x000E,
20 };
21
22 enum { /* Commands */
23 GlobalReset = 0x0000,
24 SelectRegisterWindow = 0x0001,
25 RxReset = 0x0005,
26 TxReset = 0x000B,
27 AcknowledgeInterrupt = 0x000D,
28 };
29
30 enum { /* IntStatus bits */
31 commandInProgress = 0x1000,
32 };
33
34 #define COMMAND(port, cmd, a) outs((port)+CommandR, ((cmd)<<11)|(a))
35 #define STATUS(port) ins((port)+IntStatusR)
36
37 enum { /* Window 0 - setup */
38 Wsetup = 0x0000,
39 /* registers */
40 ManufacturerID = 0x0000, /* 3C5[08]*, 3C59[27] */
41 ProductID = 0x0002, /* 3C5[08]*, 3C59[27] */
42 ConfigControl = 0x0004, /* 3C5[08]*, 3C59[27] */
43 AddressConfig = 0x0006, /* 3C5[08]*, 3C59[27] */
44 ResourceConfig = 0x0008, /* 3C5[08]*, 3C59[27] */
45 EepromCommand = 0x000A,
46 EepromData = 0x000C,
47 /* AddressConfig Bits */
48 autoSelect9 = 0x0080,
49 xcvrMask9 = 0xC000,
50 /* ConfigControl bits */
51 Ena = 0x0001,
52 base10TAvailable9 = 0x0200,
53 coaxAvailable9 = 0x1000,
54 auiAvailable9 = 0x2000,
55 /* EepromCommand bits */
56 EepromReadRegister = 0x0080,
57 EepromBusy = 0x8000,
58 };
59
60 enum { /* Window 1 - operating set */
61 Wop = 0x0001,
62 };
63
64 enum { /* Window 3 - FIFO management */
65 Wfifo = 0x0003,
66 /* registers */
67 InternalConfig = 0x0000, /* 3C509B, 3C589, 3C59[0257] */
68 /* InternalConfig bits */
69 xcvr10BaseT = 0x00000000,
70 xcvr10Base2 = 0x00300000,
71 };
72
73 enum { /* Window 4 - diagnostic */
74 Wdiagnostic = 0x0004,
75 /* registers */
76 MediaStatus = 0x000A,
77 /* MediaStatus bits */
78 linkBeatDetect = 0x0800,
79 };
80
81 extern int etherelnk3reset(Ether*);
82
83 static char *tcmpcmcia[] = {
84 "3C589", /* 3COM 589[ABCD] */
85 "3C562", /* 3COM 562 */
86 "589E", /* 3COM Megahertz 589E */
87 nil,
88 };
89
90 static int
91 configASIC(Ether* ether, int port, int xcvr)
92 {
93 int x;
94
95 /* set Window 0 configuration registers */
96 COMMAND(port, SelectRegisterWindow, Wsetup);
97 outs(port+ConfigControl, Ena);
98
99 /* IRQ must be 3 on 3C589/3C562 */
100 outs(port + ResourceConfig, 0x3F00);
101
102 x = ins(port+AddressConfig) & ~xcvrMask9;
103 x |= (xcvr>>20)<<14;
104 outs(port+AddressConfig, x);
105
106 COMMAND(port, TxReset, 0);
107 while(STATUS(port) & commandInProgress)
108 ;
109 COMMAND(port, RxReset, 0);
110 while(STATUS(port) & commandInProgress)
111 ;
112
113 return etherelnk3reset(ether);
114 }
115
116 static int
117 reset(Ether* ether)
118 {
119 int i, t, slot;
120 char *type;
121 int port;
122 enum { WantAny, Want10BT, Want10B2 };
123 int want;
124 uchar ea[6];
125 char *p;
126
127 if(ether->irq == 0)
128 ether->irq = 10;
129 if(ether->port == 0)
130 ether->port = 0x240;
131 port = ether->port;
132
133 if(ioalloc(port, 0x10, 0, "3C589") < 0)
134 return -1;
135
136 type = nil;
137 slot = -1;
138 for(i = 0; tcmpcmcia[i] != nil; i++){
139 type = tcmpcmcia[i];
140 if((slot = pcmspecial(type, ether)) >= 0)
141 break;
142 }
143 ether->type = type; /* must be set before calling configASIC */
144 if(slot < 0){
145 iofree(port);
146 return -1;
147 }
148
149 /*
150 * Read Ethernet address from card memory
151 * on 3C562, but only if the user has not
152 * overridden it.
153 */
154 memset(ea, 0, sizeof ea);
155 if(memcmp(ea, ether->ea, 6) == 0 && strcmp(type, "3C562") == 0) {
156 if(pcmcistuple(slot, 0x88, -1, ea, 6) == 6) {
157 for(i = 0; i < 6; i += 2){
158 t = ea[i];
159 ea[i] = ea[i+1];
160 ea[i+1] = t;
161 }
162 memmove(ether->ea, ea, 6);
163 }
164 }
165 /*
166 * Allow user to specify desired media in plan9.ini
167 */
168 want = WantAny;
169 for(i = 0; i < ether->nopt; i++){
170 if(cistrncmp(ether->opt[i], "media=", 6) != 0)
171 continue;
172 p = ether->opt[i]+6;
173 if(cistrcmp(p, "10base2") == 0)
174 want = Want10B2;
175 else if(cistrcmp(p, "10baseT") == 0)
176 want = Want10BT;
177 }
178
179 /* try configuring as a 10BaseT */
180 if(want==WantAny || want==Want10BT){
181 if(configASIC(ether, port, xcvr10BaseT) < 0){
182 pcmspecialclose(slot);
183 iofree(port);
184 return -1;
185 }
186 delay(100);
187 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
188 if((ins(port+MediaStatus)&linkBeatDetect) || want==Want10BT){
189 COMMAND(port, SelectRegisterWindow, Wop);
190 print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, type);
191 return 0;
192 }
193 }
194
195 /* try configuring as a 10base2 */
196 if(want==WantAny || want==Want10B2){
197 COMMAND(port, GlobalReset, 0);
198 if(configASIC(ether, port, xcvr10Base2) < 0){
199 pcmspecialclose(slot);
200 iofree(port);
201 return -1;
202 }
203 print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, type);
204 return 0;
205 }
206 return -1; /* not reached */
207 }
208
209 void
210 ether589link(void)
211 {
212 addethercard("3C589", reset);
213 addethercard("3C562", reset);
214 addethercard("589E", reset);
215 }
Cache object: 2bf13c6c7ee29d2616c82ebd22a29d84
|