]>
Commit | Line | Data |
---|---|---|
d6aaa55d MT |
1 | /* |
2 | * PCMCIA bridge device probe | |
3 | * | |
4 | * This file is part of the IPCop Firewall. | |
5 | * | |
6 | * IPCop is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * IPCop is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with IPCop; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | * | |
20 | * The initial developer of the original code is David A. Hinds | |
21 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | |
22 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | |
23 | * | |
10bc6f06 | 24 | * $Id: pcmcia.c,v 1.6.2.2 2005/01/31 15:49:43 alanh Exp $ |
d6aaa55d MT |
25 | * |
26 | */ | |
27 | ||
28 | #include "install.h" | |
29 | #include "pcmcia.h" | |
30 | ||
31 | #ifdef __GLIBC__ | |
32 | #include <sys/io.h> | |
33 | #else | |
34 | #include <asm/io.h> | |
35 | #endif | |
36 | ||
37 | extern FILE *flog; | |
d6aaa55d MT |
38 | |
39 | /*====================================================================*/ | |
40 | ||
41 | typedef struct { | |
42 | u_short vendor, device; | |
43 | char *modname; | |
44 | char *name; | |
45 | } pci_id_t; | |
46 | ||
47 | pci_id_t pci_id[] = { | |
48 | { 0x1013, 0x1100, "i82365", "Cirrus Logic CL 6729" }, | |
49 | { 0x1013, 0x1110, "yenta_socket", "Cirrus Logic PD 6832" }, | |
50 | { 0x10b3, 0xb106, "yenta_socket", "SMC 34C90" }, | |
51 | { 0x1180, 0x0465, "yenta_socket", "Ricoh RL5C465" }, | |
52 | { 0x1180, 0x0466, "yenta_socket", "Ricoh RL5C466" }, | |
53 | { 0x1180, 0x0475, "yenta_socket", "Ricoh RL5C475" }, | |
54 | { 0x1180, 0x0476, "yenta_socket", "Ricoh RL5C476" }, | |
55 | { 0x1180, 0x0477, "yenta_socket", "Ricoh RL5C477" }, | |
56 | { 0x1180, 0x0478, "yenta_socket", "Ricoh RL5C478" }, | |
57 | { 0x104c, 0xac12, "yenta_socket", "Texas Instruments PCI1130" }, | |
58 | { 0x104c, 0xac13, "yenta_socket", "Texas Instruments PCI1031" }, | |
59 | { 0x104c, 0xac15, "yenta_socket", "Texas Instruments PCI1131" }, | |
60 | { 0x104c, 0xac1a, "yenta_socket", "Texas Instruments PCI1210" }, | |
61 | { 0x104c, 0xac1e, "yenta_socket", "Texas Instruments PCI1211" }, | |
62 | { 0x104c, 0xac17, "yenta_socket", "Texas Instruments PCI1220" }, | |
63 | { 0x104c, 0xac19, "yenta_socket", "Texas Instruments PCI1221" }, | |
64 | { 0x104c, 0xac1c, "yenta_socket", "Texas Instruments PCI1225" }, | |
65 | { 0x104c, 0xac16, "yenta_socket", "Texas Instruments PCI1250" }, | |
66 | { 0x104c, 0xac1d, "yenta_socket", "Texas Instruments PCI1251A" }, | |
67 | { 0x104c, 0xac1f, "yenta_socket", "Texas Instruments PCI1251B" }, | |
68 | { 0x104c, 0xac50, "yenta_socket", "Texas Instruments PCI1410" }, | |
69 | { 0x104c, 0xac51, "yenta_socket", "Texas Instruments PCI1420" }, | |
70 | { 0x104c, 0xac1b, "yenta_socket", "Texas Instruments PCI1450" }, | |
71 | { 0x104c, 0xac52, "yenta_socket", "Texas Instruments PCI1451" }, | |
72 | { 0x104c, 0xac56, "yenta_socket", "Texas Instruments PCI1510" }, | |
73 | { 0x104c, 0xac55, "yenta_socket", "Texas Instruments PCI1520" }, | |
74 | { 0x104c, 0xac54, "yenta_socket", "Texas Instruments PCI1620" }, | |
75 | { 0x104c, 0xac41, "yenta_socket", "Texas Instruments PCI4410" }, | |
76 | { 0x104c, 0xac40, "yenta_socket", "Texas Instruments PCI4450" }, | |
77 | { 0x104c, 0xac42, "yenta_socket", "Texas Instruments PCI4451" }, | |
78 | { 0x104c, 0xac44, "yenta_socket", "Texas Instruments PCI4510" }, | |
79 | { 0x104c, 0xac46, "yenta_socket", "Texas Instruments PCI4520" }, | |
80 | { 0x104c, 0xac49, "yenta_socket", "Texas Instruments PCI7410" }, | |
81 | { 0x104c, 0xac47, "yenta_socket", "Texas Instruments PCI7510" }, | |
82 | { 0x104c, 0xac48, "yenta_socket", "Texas Instruments PCI7610" }, | |
83 | { 0x1217, 0x6729, "i82365", "O2 Micro 6729" }, | |
84 | { 0x1217, 0x673a, "i82365", "O2 Micro 6730" }, | |
85 | { 0x1217, 0x6832, "yenta_socket", "O2 Micro 6832/6833" }, | |
86 | { 0x1217, 0x6836, "yenta_socket", "O2 Micro 6836/6860" }, | |
87 | { 0x1217, 0x6872, "yenta_socket", "O2 Micro 6812" }, | |
88 | { 0x1217, 0x6925, "yenta_socket", "O2 Micro 6922" }, | |
89 | { 0x1217, 0x6933, "yenta_socket", "O2 Micro 6933" }, | |
90 | { 0x1217, 0x6972, "yenta_socket", "O2 Micro 6912" }, | |
91 | { 0x1179, 0x0603, "i82365", "Toshiba ToPIC95-A" }, | |
92 | { 0x1179, 0x060a, "yenta_socket", "Toshiba ToPIC95-B" }, | |
93 | { 0x1179, 0x060f, "yenta_socket", "Toshiba ToPIC97" }, | |
94 | { 0x1179, 0x0617, "yenta_socket", "Toshiba ToPIC100" }, | |
95 | { 0x119b, 0x1221, "i82365", "Omega Micro 82C092G" }, | |
96 | { 0x8086, 0x1221, "i82092", "Intel 82092AA_0" }, | |
97 | { 0x8086, 0x1222, "i82092", "Intel 82092AA_1" }, | |
98 | { 0x1524, 0x1211, "yenta_socket", "ENE 1211" }, | |
99 | { 0x1524, 0x1225, "yenta_socket", "ENE 1225" }, | |
100 | { 0x1524, 0x1410, "yenta_socket", "ENE 1410" }, | |
101 | { 0x1524, 0x1420, "yenta_socket", "ENE 1420" }, | |
102 | }; | |
103 | #define PCI_COUNT (sizeof(pci_id)/sizeof(pci_id_t)) | |
104 | ||
105 | static char * pci_probe() | |
106 | { | |
107 | char s[256], *modname = NULL; | |
108 | u_int device, vendor, i; | |
109 | FILE *f; | |
110 | ||
111 | if ((f = fopen("/proc/bus/pci/devices", "r")) != NULL) { | |
112 | while (fgets(s, 256, f) != NULL) { | |
113 | u_int n = strtoul(s+5, NULL, 16); | |
114 | vendor = (n >> 16); device = (n & 0xffff); | |
115 | for (i = 0; i < PCI_COUNT; i++) | |
116 | if ((vendor == pci_id[i].vendor) && | |
117 | (device == pci_id[i].device)) break; | |
118 | ||
119 | if (i < PCI_COUNT) { | |
120 | modname = pci_id[i].modname; | |
121 | break; | |
122 | } | |
123 | } | |
124 | } | |
125 | ||
126 | return modname; | |
127 | } | |
128 | ||
129 | /*====================================================================*/ | |
130 | ||
131 | #ifndef __alpha__ | |
132 | typedef u_short ioaddr_t; | |
133 | ||
134 | static ioaddr_t i365_base = 0x03e0; | |
135 | ||
136 | static u_char i365_get(u_short sock, u_short reg) | |
137 | { | |
138 | u_char val = I365_REG(sock, reg); | |
139 | outb(val, i365_base); val = inb(i365_base+1); | |
140 | return val; | |
141 | } | |
142 | ||
d6aaa55d MT |
143 | static void i365_set(u_short sock, u_short reg, u_char data) |
144 | { | |
145 | u_char val = I365_REG(sock, reg); | |
146 | outb(val, i365_base); outb(data, i365_base+1); | |
147 | } | |
148 | ||
149 | static void i365_bset(u_short sock, u_short reg, u_char mask) | |
150 | { | |
151 | u_char d = i365_get(sock, reg); | |
152 | d |= mask; | |
153 | i365_set(sock, reg, d); | |
154 | } | |
155 | ||
156 | static void i365_bclr(u_short sock, u_short reg, u_char mask) | |
157 | { | |
158 | u_char d = i365_get(sock, reg); | |
159 | d &= ~mask; | |
160 | i365_set(sock, reg, d); | |
161 | } | |
d6aaa55d MT |
162 | |
163 | int i365_probe() | |
164 | { | |
165 | int val, slot, sock, done; | |
10bc6f06 | 166 | char *name = "i82365sl"; |
d6aaa55d MT |
167 | |
168 | ioperm(i365_base, 4, 1); | |
169 | ioperm(0x80, 1, 1); | |
170 | for (slot = 0; slot < 2; slot++) { | |
171 | for (sock = done = 0; sock < 2; sock++) { | |
172 | val = i365_get(sock, I365_IDENT); | |
173 | switch (val) { | |
174 | case 0x82: | |
10bc6f06 MT |
175 | name = "i82365sl A step"; |
176 | break; | |
d6aaa55d | 177 | case 0x83: |
10bc6f06 MT |
178 | name = "i82365sl B step"; |
179 | break; | |
d6aaa55d | 180 | case 0x84: |
10bc6f06 MT |
181 | name = "VLSI 82C146"; |
182 | break; | |
d6aaa55d | 183 | case 0x88: case 0x89: case 0x8a: |
10bc6f06 MT |
184 | name = "IBM Clone"; |
185 | break; | |
d6aaa55d MT |
186 | case 0x8b: case 0x8c: |
187 | break; | |
188 | default: | |
189 | done = 1; | |
190 | } | |
191 | if (done) break; | |
192 | } | |
193 | if (done && sock) break; | |
194 | i365_base += 2; | |
195 | } | |
196 | ||
197 | if (sock == 0) { | |
198 | return -1; | |
199 | } | |
200 | ||
d6aaa55d MT |
201 | if ((sock == 2) && (strcmp(name, "VLSI 82C146") == 0)) |
202 | name = "i82365sl DF"; | |
203 | ||
204 | /* Check for Vadem chips */ | |
205 | outb(0x0e, i365_base); | |
206 | outb(0x37, i365_base); | |
207 | i365_bset(0, VG468_MISC, VG468_MISC_VADEMREV); | |
208 | val = i365_get(0, I365_IDENT); | |
209 | if (val & I365_IDENT_VADEM) { | |
210 | if ((val & 7) < 4) | |
211 | name = "Vadem VG-468"; | |
212 | else | |
213 | name = "Vadem VG-469"; | |
214 | i365_bclr(0, VG468_MISC, VG468_MISC_VADEMREV); | |
215 | } | |
216 | ||
217 | /* Check for Cirrus CL-PD67xx chips */ | |
218 | i365_set(0, PD67_CHIP_INFO, 0); | |
219 | val = i365_get(0, PD67_CHIP_INFO); | |
220 | if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) { | |
221 | val = i365_get(0, PD67_CHIP_INFO); | |
222 | if ((val & PD67_INFO_CHIP_ID) == 0) { | |
223 | if (val & PD67_INFO_SLOTS) | |
224 | name = "Cirrus CL-PD672x"; | |
225 | else { | |
226 | name = "Cirrus CL-PD6710"; | |
227 | sock = 1; | |
228 | } | |
229 | i365_set(0, PD67_EXT_INDEX, 0xe5); | |
230 | if (i365_get(0, PD67_EXT_INDEX) != 0xe5) | |
231 | name = "VIA VT83C469"; | |
232 | } | |
233 | } | |
10bc6f06 | 234 | |
d6aaa55d MT |
235 | return 0; |
236 | ||
237 | } /* i365_probe */ | |
238 | #endif | |
239 | ||
240 | /*====================================================================*/ | |
241 | ||
242 | #ifndef __alpha__ | |
243 | static u_short tcic_getw(ioaddr_t base, u_char reg) | |
244 | { | |
245 | u_short val = inw(base+reg); | |
246 | return val; | |
247 | } | |
248 | ||
249 | static void tcic_setw(ioaddr_t base, u_char reg, u_short data) | |
250 | { | |
251 | outw(data, base+reg); | |
252 | } | |
253 | ||
254 | int tcic_probe_at(ioaddr_t base) | |
255 | { | |
256 | int i; | |
257 | u_short old; | |
258 | ||
259 | /* Anything there?? */ | |
260 | for (i = 0; i < 0x10; i += 2) | |
261 | if (tcic_getw(base, i) == 0xffff) | |
262 | return -1; | |
263 | ||
264 | /* Try to reset the chip */ | |
265 | tcic_setw(base, TCIC_SCTRL, TCIC_SCTRL_RESET); | |
266 | tcic_setw(base, TCIC_SCTRL, 0); | |
267 | ||
268 | /* Can we set the addr register? */ | |
269 | old = tcic_getw(base, TCIC_ADDR); | |
270 | tcic_setw(base, TCIC_ADDR, 0); | |
271 | if (tcic_getw(base, TCIC_ADDR) != 0) { | |
272 | tcic_setw(base, TCIC_ADDR, old); | |
273 | return -2; | |
274 | } | |
275 | ||
276 | tcic_setw(base, TCIC_ADDR, 0xc3a5); | |
277 | if (tcic_getw(base, TCIC_ADDR) != 0xc3a5) | |
278 | return -3; | |
279 | ||
280 | return 2; | |
281 | } | |
282 | ||
283 | int tcic_probe(ioaddr_t base) | |
284 | { | |
285 | int sock; | |
286 | ||
287 | ioperm(base, 16, 1); | |
288 | ioperm(0x80, 1, 1); | |
289 | sock = tcic_probe_at(base); | |
290 | ||
291 | if (sock <= 0) { | |
292 | return -1; | |
293 | } | |
294 | ||
295 | return 0; | |
296 | ||
297 | } /* tcic_probe */ | |
298 | #endif | |
299 | ||
300 | /*====================================================================*/ | |
10bc6f06 | 301 | |
d6aaa55d MT |
302 | char * initialize_pcmcia (void) |
303 | { | |
304 | #ifndef __alpha__ | |
305 | ioaddr_t tcic_base = TCIC_BASE; | |
306 | #endif | |
10bc6f06 MT |
307 | int len; |
308 | char *pcmcia = NULL; | |
309 | ||
310 | if ((pcmcia = pci_probe())) { | |
311 | /* we're all done */ | |
d6aaa55d | 312 | #ifndef __alpha__ |
10bc6f06 MT |
313 | } else if (i365_probe() == 0) { |
314 | len = strlen("i82365") + 1; | |
315 | pcmcia = calloc(1, len); | |
316 | strncpy(pcmcia, "i82365", len); | |
317 | } else if (tcic_probe(tcic_base) == 0) { | |
318 | len = strlen("tcic") + 1; | |
319 | pcmcia = calloc(1, len); | |
320 | strncpy(pcmcia, "tcic", len); | |
d6aaa55d | 321 | #endif |
10bc6f06 | 322 | } else { |
d6aaa55d MT |
323 | /* Detect ISAPNP based i82365 controllers */ |
324 | FILE *f; | |
10bc6f06 | 325 | mysystem("modprobe i82365"); |
d6aaa55d | 326 | if ((f = fopen("/proc/bus/pccard/00/info", "r"))) { |
10bc6f06 MT |
327 | len = strlen("i82365") + 1; |
328 | pcmcia = calloc(1, len); | |
329 | strncpy(pcmcia, "i82365", len); | |
d6aaa55d | 330 | fclose(f); |
d6aaa55d MT |
331 | } |
332 | } | |
333 | ||
10bc6f06 | 334 | return pcmcia; |
d6aaa55d | 335 | } |