]>
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 | * | |
24 | * $Id: pcmcia.c,v 1.6.2.4 2005/12/08 02:12:28 franck78 Exp $ | |
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; | |
38 | extern int modprobe(char *); | |
39 | ||
40 | /*====================================================================*/ | |
41 | ||
42 | typedef struct { | |
43 | u_short vendor, device; | |
44 | char *modname; | |
45 | char *name; | |
46 | } pci_id_t; | |
47 | ||
48 | pci_id_t pci_id[] = { | |
49 | { 0x1013, 0x1100, "i82365", "Cirrus Logic CL 6729" }, | |
50 | { 0x1013, 0x1110, "yenta_socket", "Cirrus Logic PD 6832" }, | |
51 | { 0x10b3, 0xb106, "yenta_socket", "SMC 34C90" }, | |
52 | { 0x1180, 0x0465, "yenta_socket", "Ricoh RL5C465" }, | |
53 | { 0x1180, 0x0466, "yenta_socket", "Ricoh RL5C466" }, | |
54 | { 0x1180, 0x0475, "yenta_socket", "Ricoh RL5C475" }, | |
55 | { 0x1180, 0x0476, "yenta_socket", "Ricoh RL5C476" }, | |
56 | { 0x1180, 0x0477, "yenta_socket", "Ricoh RL5C477" }, | |
57 | { 0x1180, 0x0478, "yenta_socket", "Ricoh RL5C478" }, | |
58 | { 0x104c, 0xac12, "yenta_socket", "Texas Instruments PCI1130" }, | |
59 | { 0x104c, 0xac13, "yenta_socket", "Texas Instruments PCI1031" }, | |
60 | { 0x104c, 0xac15, "yenta_socket", "Texas Instruments PCI1131" }, | |
61 | { 0x104c, 0xac1a, "yenta_socket", "Texas Instruments PCI1210" }, | |
62 | { 0x104c, 0xac1e, "yenta_socket", "Texas Instruments PCI1211" }, | |
63 | { 0x104c, 0xac17, "yenta_socket", "Texas Instruments PCI1220" }, | |
64 | { 0x104c, 0xac19, "yenta_socket", "Texas Instruments PCI1221" }, | |
65 | { 0x104c, 0xac1c, "yenta_socket", "Texas Instruments PCI1225" }, | |
66 | { 0x104c, 0xac16, "yenta_socket", "Texas Instruments PCI1250" }, | |
67 | { 0x104c, 0xac1d, "yenta_socket", "Texas Instruments PCI1251A" }, | |
68 | { 0x104c, 0xac1f, "yenta_socket", "Texas Instruments PCI1251B" }, | |
69 | { 0x104c, 0xac50, "yenta_socket", "Texas Instruments PCI1410" }, | |
70 | { 0x104c, 0xac51, "yenta_socket", "Texas Instruments PCI1420" }, | |
71 | { 0x104c, 0xac1b, "yenta_socket", "Texas Instruments PCI1450" }, | |
72 | { 0x104c, 0xac52, "yenta_socket", "Texas Instruments PCI1451" }, | |
73 | { 0x104c, 0xac56, "yenta_socket", "Texas Instruments PCI1510" }, | |
74 | { 0x104c, 0xac55, "yenta_socket", "Texas Instruments PCI1520" }, | |
75 | { 0x104c, 0xac54, "yenta_socket", "Texas Instruments PCI1620" }, | |
76 | { 0x104c, 0xac41, "yenta_socket", "Texas Instruments PCI4410" }, | |
77 | { 0x104c, 0xac40, "yenta_socket", "Texas Instruments PCI4450" }, | |
78 | { 0x104c, 0xac42, "yenta_socket", "Texas Instruments PCI4451" }, | |
79 | { 0x104c, 0xac44, "yenta_socket", "Texas Instruments PCI4510" }, | |
80 | { 0x104c, 0xac46, "yenta_socket", "Texas Instruments PCI4520" }, | |
81 | { 0x104c, 0xac49, "yenta_socket", "Texas Instruments PCI7410" }, | |
82 | { 0x104c, 0xac47, "yenta_socket", "Texas Instruments PCI7510" }, | |
83 | { 0x104c, 0xac48, "yenta_socket", "Texas Instruments PCI7610" }, | |
84 | { 0x1217, 0x6729, "i82365", "O2 Micro 6729" }, | |
85 | { 0x1217, 0x673a, "i82365", "O2 Micro 6730" }, | |
86 | { 0x1217, 0x6832, "yenta_socket", "O2 Micro 6832/6833" }, | |
87 | { 0x1217, 0x6836, "yenta_socket", "O2 Micro 6836/6860" }, | |
88 | { 0x1217, 0x6872, "yenta_socket", "O2 Micro 6812" }, | |
89 | { 0x1217, 0x6925, "yenta_socket", "O2 Micro 6922" }, | |
90 | { 0x1217, 0x6933, "yenta_socket", "O2 Micro 6933" }, | |
91 | { 0x1217, 0x6972, "yenta_socket", "O2 Micro 6912" }, | |
92 | { 0x1179, 0x0603, "i82365", "Toshiba ToPIC95-A" }, | |
93 | { 0x1179, 0x060a, "yenta_socket", "Toshiba ToPIC95-B" }, | |
94 | { 0x1179, 0x060f, "yenta_socket", "Toshiba ToPIC97" }, | |
95 | { 0x1179, 0x0617, "yenta_socket", "Toshiba ToPIC100" }, | |
96 | { 0x119b, 0x1221, "i82365", "Omega Micro 82C092G" }, | |
97 | { 0x8086, 0x1221, "i82092", "Intel 82092AA_0" }, | |
98 | { 0x8086, 0x1222, "i82092", "Intel 82092AA_1" }, | |
99 | { 0x1524, 0x1211, "yenta_socket", "ENE 1211" }, | |
100 | { 0x1524, 0x1225, "yenta_socket", "ENE 1225" }, | |
101 | { 0x1524, 0x1410, "yenta_socket", "ENE 1410" }, | |
102 | { 0x1524, 0x1420, "yenta_socket", "ENE 1420" }, | |
103 | }; | |
104 | #define PCI_COUNT (sizeof(pci_id)/sizeof(pci_id_t)) | |
105 | ||
106 | static char * pci_probe() | |
107 | { | |
108 | char s[256], *modname = NULL; | |
109 | u_int device, vendor, i; | |
110 | FILE *f; | |
111 | ||
112 | if ((f = fopen("/proc/bus/pci/devices", "r")) != NULL) { | |
113 | while (fgets(s, 256, f) != NULL) { | |
114 | u_int n = strtoul(s+5, NULL, 16); | |
115 | vendor = (n >> 16); device = (n & 0xffff); | |
116 | for (i = 0; i < PCI_COUNT; i++) | |
117 | if ((vendor == pci_id[i].vendor) && | |
118 | (device == pci_id[i].device)) break; | |
119 | ||
120 | if (i < PCI_COUNT) { | |
121 | modname = pci_id[i].modname; | |
122 | break; | |
123 | } | |
124 | } | |
125 | } | |
126 | ||
127 | return modname; | |
128 | } | |
129 | ||
130 | /*====================================================================*/ | |
131 | ||
132 | #ifndef __alpha__ | |
133 | typedef u_short ioaddr_t; | |
134 | ||
135 | static ioaddr_t i365_base = 0x03e0; | |
136 | ||
137 | static u_char i365_get(u_short sock, u_short reg) | |
138 | { | |
139 | u_char val = I365_REG(sock, reg); | |
140 | outb(val, i365_base); val = inb(i365_base+1); | |
141 | return val; | |
142 | } | |
143 | ||
144 | #if 0 // the following code do nothing usefull, it ends with return 0 anyway | |
145 | ||
146 | static void i365_set(u_short sock, u_short reg, u_char data) | |
147 | { | |
148 | u_char val = I365_REG(sock, reg); | |
149 | outb(val, i365_base); outb(data, i365_base+1); | |
150 | } | |
151 | ||
152 | static void i365_bset(u_short sock, u_short reg, u_char mask) | |
153 | { | |
154 | u_char d = i365_get(sock, reg); | |
155 | d |= mask; | |
156 | i365_set(sock, reg, d); | |
157 | } | |
158 | ||
159 | static void i365_bclr(u_short sock, u_short reg, u_char mask) | |
160 | { | |
161 | u_char d = i365_get(sock, reg); | |
162 | d &= ~mask; | |
163 | i365_set(sock, reg, d); | |
164 | } | |
165 | #endif | |
166 | ||
167 | int i365_probe() | |
168 | { | |
169 | int val, slot, sock, done; | |
170 | // char *name = "i82365sl"; | |
171 | ||
172 | ioperm(i365_base, 4, 1); | |
173 | ioperm(0x80, 1, 1); | |
174 | for (slot = 0; slot < 2; slot++) { | |
175 | for (sock = done = 0; sock < 2; sock++) { | |
176 | val = i365_get(sock, I365_IDENT); | |
177 | switch (val) { | |
178 | case 0x82: | |
179 | // name = "i82365sl A step"; | |
180 | // break; | |
181 | case 0x83: | |
182 | // name = "i82365sl B step"; | |
183 | // break; | |
184 | case 0x84: | |
185 | // name = "VLSI 82C146"; | |
186 | // break; | |
187 | case 0x88: case 0x89: case 0x8a: | |
188 | // name = "IBM Clone"; | |
189 | // break; | |
190 | case 0x8b: case 0x8c: | |
191 | break; | |
192 | default: | |
193 | done = 1; | |
194 | } | |
195 | if (done) break; | |
196 | } | |
197 | if (done && sock) break; | |
198 | i365_base += 2; | |
199 | } | |
200 | ||
201 | if (sock == 0) { | |
202 | return -1; | |
203 | } | |
204 | ||
205 | #if 0 // the following code do nothing usefull, it ends with return 0 anyway | |
206 | if ((sock == 2) && (strcmp(name, "VLSI 82C146") == 0)) | |
207 | name = "i82365sl DF"; | |
208 | ||
209 | /* Check for Vadem chips */ | |
210 | outb(0x0e, i365_base); | |
211 | outb(0x37, i365_base); | |
212 | i365_bset(0, VG468_MISC, VG468_MISC_VADEMREV); | |
213 | val = i365_get(0, I365_IDENT); | |
214 | if (val & I365_IDENT_VADEM) { | |
215 | if ((val & 7) < 4) | |
216 | name = "Vadem VG-468"; | |
217 | else | |
218 | name = "Vadem VG-469"; | |
219 | i365_bclr(0, VG468_MISC, VG468_MISC_VADEMREV); | |
220 | } | |
221 | ||
222 | /* Check for Cirrus CL-PD67xx chips */ | |
223 | i365_set(0, PD67_CHIP_INFO, 0); | |
224 | val = i365_get(0, PD67_CHIP_INFO); | |
225 | if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) { | |
226 | val = i365_get(0, PD67_CHIP_INFO); | |
227 | if ((val & PD67_INFO_CHIP_ID) == 0) { | |
228 | if (val & PD67_INFO_SLOTS) | |
229 | name = "Cirrus CL-PD672x"; | |
230 | else { | |
231 | name = "Cirrus CL-PD6710"; | |
232 | sock = 1; | |
233 | } | |
234 | i365_set(0, PD67_EXT_INDEX, 0xe5); | |
235 | if (i365_get(0, PD67_EXT_INDEX) != 0xe5) | |
236 | name = "VIA VT83C469"; | |
237 | } | |
238 | } | |
239 | #endif | |
240 | return 0; | |
241 | ||
242 | } /* i365_probe */ | |
243 | #endif | |
244 | ||
245 | /*====================================================================*/ | |
246 | ||
247 | #ifndef __alpha__ | |
248 | static u_short tcic_getw(ioaddr_t base, u_char reg) | |
249 | { | |
250 | u_short val = inw(base+reg); | |
251 | return val; | |
252 | } | |
253 | ||
254 | static void tcic_setw(ioaddr_t base, u_char reg, u_short data) | |
255 | { | |
256 | outw(data, base+reg); | |
257 | } | |
258 | ||
259 | int tcic_probe_at(ioaddr_t base) | |
260 | { | |
261 | int i; | |
262 | u_short old; | |
263 | ||
264 | /* Anything there?? */ | |
265 | for (i = 0; i < 0x10; i += 2) | |
266 | if (tcic_getw(base, i) == 0xffff) | |
267 | return -1; | |
268 | ||
269 | /* Try to reset the chip */ | |
270 | tcic_setw(base, TCIC_SCTRL, TCIC_SCTRL_RESET); | |
271 | tcic_setw(base, TCIC_SCTRL, 0); | |
272 | ||
273 | /* Can we set the addr register? */ | |
274 | old = tcic_getw(base, TCIC_ADDR); | |
275 | tcic_setw(base, TCIC_ADDR, 0); | |
276 | if (tcic_getw(base, TCIC_ADDR) != 0) { | |
277 | tcic_setw(base, TCIC_ADDR, old); | |
278 | return -2; | |
279 | } | |
280 | ||
281 | tcic_setw(base, TCIC_ADDR, 0xc3a5); | |
282 | if (tcic_getw(base, TCIC_ADDR) != 0xc3a5) | |
283 | return -3; | |
284 | ||
285 | return 2; | |
286 | } | |
287 | ||
288 | int tcic_probe(ioaddr_t base) | |
289 | { | |
290 | int sock; | |
291 | ||
292 | ioperm(base, 16, 1); | |
293 | ioperm(0x80, 1, 1); | |
294 | sock = tcic_probe_at(base); | |
295 | ||
296 | if (sock <= 0) { | |
297 | return -1; | |
298 | } | |
299 | ||
300 | return 0; | |
301 | ||
302 | } /* tcic_probe */ | |
303 | #endif | |
304 | ||
305 | /*====================================================================*/ | |
306 | char * initialize_pcmcia (void) | |
307 | { | |
308 | #ifndef __alpha__ | |
309 | ioaddr_t tcic_base = TCIC_BASE; | |
310 | #endif | |
311 | char* pcmcia; | |
312 | ||
313 | if ((pcmcia = pci_probe())) | |
314 | return pcmcia; /* we're all done */ | |
315 | #ifndef __alpha__ | |
316 | else if (i365_probe() == 0) | |
317 | return "i82365"; | |
318 | else if (tcic_probe(tcic_base) == 0) | |
319 | return "tcic"; | |
320 | #endif | |
321 | else { | |
322 | /* Detect ISAPNP based i82365 controllers */ | |
323 | FILE *f; | |
324 | modprobe("i82365"); | |
325 | if ((f = fopen("/proc/bus/pccard/00/info", "r"))) { | |
326 | fclose(f); | |
327 | return "i82365"; | |
328 | } | |
329 | } | |
330 | ||
331 | return NULL; | |
332 | } |