]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ether589.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / 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 #include "../port/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 etherelnk3reset(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 etherelnk3reset(ether);
113 }
114
115 static int
116 reset(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((slot = pcmspecial(type, ether)) >= 0)
140                         break;
141         }
142         ether->type = type;     /* must be set before calling configASIC */
143         if(slot < 0){
144                 iofree(port);
145                 return -1;
146         }
147
148         /*
149          * Read Ethernet address from card memory
150          * on 3C562, but only if the user has not 
151          * overridden it.
152          */
153         memset(ea, 0, sizeof ea);
154         if(memcmp(ea, ether->ea, 6) == 0 && strcmp(type, "3C562") == 0) {
155                 if(pcmcistuple(slot, 0x88, -1, ea, 6) == 6) {
156                         for(i = 0; i < 6; i += 2){
157                                 t = ea[i];
158                                 ea[i] = ea[i+1];
159                                 ea[i+1] = t;
160                         }
161                         memmove(ether->ea, ea, 6);
162                 }
163         }
164         /*
165          * Allow user to specify desired media in plan9.ini
166          */
167         want = WantAny;
168         for(i = 0; i < ether->nopt; i++){
169                 if(cistrncmp(ether->opt[i], "media=", 6) != 0)
170                         continue;
171                 p = ether->opt[i]+6;
172                 if(cistrcmp(p, "10base2") == 0)
173                         want = Want10B2;
174                 else if(cistrcmp(p, "10baseT") == 0)
175                         want = Want10BT;
176         }
177         
178         /* try configuring as a 10BaseT */
179         if(want==WantAny || want==Want10BT){
180                 if(configASIC(ether, port, xcvr10BaseT) < 0){
181                         pcmspecialclose(slot);
182                         iofree(port);
183                         return -1;
184                 }
185                 delay(100);
186                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
187                 if((ins(port+MediaStatus)&linkBeatDetect) || want==Want10BT){
188                         COMMAND(port, SelectRegisterWindow, Wop);
189                         print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, type);
190                         return 0;
191                 }
192         }
193
194         /* try configuring as a 10base2 */
195         if(want==WantAny || want==Want10B2){
196                 COMMAND(port, GlobalReset, 0);
197                 if(configASIC(ether, port, xcvr10Base2) < 0){
198                         pcmspecialclose(slot);
199                         iofree(port);
200                         return -1;
201                 }
202                 print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, type);
203                 return 0;
204         }
205         return -1;              /* not reached */
206 }
207
208 void
209 ether589link(void)
210 {
211         addethercard("3C589", reset);
212         addethercard("3C562", reset);
213         addethercard("589E", reset);
214 }