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