]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ether589.c
Import sources from 2011-03-30 iso image
[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
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 }