isapnpres.c revision 1.2 1 /* $NetBSD: isapnpres.c,v 1.2 1997/01/22 23:51:38 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1996 Christos Zoulas. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Christos Zoulas.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Resource parser for Plug and Play cards.
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40
41 #include <machine/bus.h>
42
43 #include <dev/isa/isavar.h>
44
45 #include <dev/isapnp/isapnpreg.h>
46 #include <dev/isapnp/isapnpvar.h>
47
48
49 static int isapnp_wait_status __P((struct isapnp_softc *));
50 static struct isapnp_attach_args *isapnp_process_tag __P((u_char, u_char,
51 u_char *, struct isapnp_attach_args *));
52
53
54 /* isapnp_wait_status():
55 * Wait for the next byte of resource data to become available
56 */
57 static int
58 isapnp_wait_status(sc)
59 struct isapnp_softc *sc;
60 {
61 int i;
62
63 for (i = 0; i < 10; i++) {
64 if (isapnp_read_reg(sc, ISAPNP_STATUS) & 1)
65 return 0;
66 DELAY(100);
67 }
68 return 1;
69 }
70
71 /* isapnp_process_tag():
72 * Process a resource tag
73 */
74 static struct isapnp_attach_args *
75 isapnp_process_tag(tag, len, buf, pa)
76 u_char tag, len, *buf;
77 struct isapnp_attach_args *pa;
78 {
79 struct isapnp_attach_args *npa;
80 char str[64];
81 struct isapnp_region *r;
82 struct isapnp_pin *p;
83
84 #define COPY(a, b) strncpy((a), (b), sizeof(a)), (a)[sizeof(a) - 1] = '\0'
85
86 switch (tag) {
87 case ISAPNP_TAG_VERSION_NUM:
88 DPRINTF(("PnP version %d.%d, Vendor version %d.%d\n",
89 buf[0] >> 4, buf[0] & 0xf, buf[1] >> 4, buf[1] & 0xf));
90 break;
91
92 case ISAPNP_TAG_LOGICAL_DEV_ID:
93 (void) isapnp_id_to_vendor(str, buf);
94 DPRINTF(("Logical device id %s\n", str));
95 COPY(pa->ipa_devlogic, str);
96 break;
97
98 case ISAPNP_TAG_COMPAT_DEV_ID:
99 (void) isapnp_id_to_vendor(str, buf);
100 DPRINTF(("Compatible device id %s\n", str));
101 break;
102
103 case ISAPNP_TAG_IRQ_FORMAT:
104 if (len < 2)
105 break;
106
107 if (len != 3)
108 buf[2] = ISAPNP_IRQTYPE_EDGE_PLUS;
109
110 p = &pa->ipa_irq[pa->ipa_nirq++];
111 p->bits = buf[0] | (buf[1] << 8);
112 p->flags = buf[2];
113 #ifdef DEBUG_ISAPNP
114 isapnp_print_irq("", p);
115 #endif
116 break;
117
118 case ISAPNP_TAG_DMA_FORMAT:
119 if (buf[0] == 0)
120 break;
121
122 p = &pa->ipa_drq[pa->ipa_ndrq++];
123 p->bits = buf[0];
124 p->flags = buf[1];
125 #ifdef DEBUG_ISAPNP
126 isapnp_print_drq("", p);
127 #endif
128 break;
129
130 case ISAPNP_TAG_DEP_START:
131 if (len == 0)
132 buf[0] = ISAPNP_DEP_ACCEPTABLE;
133 if (pa->ipa_pref != ISAPNP_DEP_UNSET) {
134 npa = ISAPNP_MALLOC(sizeof(*npa));
135 memset(npa, 0, sizeof(*npa));
136 memcpy(npa->ipa_devident, pa->ipa_devident,
137 sizeof(pa->ipa_devident));
138 memcpy(npa->ipa_devlogic, pa->ipa_devlogic,
139 sizeof(pa->ipa_devlogic));
140 memcpy(npa->ipa_devclass, pa->ipa_devclass,
141 sizeof(pa->ipa_devclass));
142 pa->ipa_next = npa;
143 pa = npa;
144 }
145 pa->ipa_pref = buf[0];
146 #ifdef DEBUG_ISAPNP
147 isapnp_print_dep_start(">>> Start dependent functions ",
148 pa->ipa_pref);
149 #endif
150 break;
151
152 case ISAPNP_TAG_DEP_END:
153 DPRINTF(("<<<End dependend functions\n"));
154 npa = ISAPNP_MALLOC(sizeof(*npa));
155 memset(npa, 0, sizeof(*npa));
156 npa->ipa_pref = ISAPNP_DEP_UNSET;
157 memcpy(npa->ipa_devident, pa->ipa_devident,
158 sizeof(pa->ipa_devident));
159
160 pa->ipa_next = npa;
161 pa = npa;
162 break;
163
164 case ISAPNP_TAG_IO_PORT_DESC:
165 r = &pa->ipa_io[pa->ipa_nio++];
166 r->flags = buf[0];
167 r->minbase = (buf[2] << 8) | buf[1];
168 r->maxbase = (buf[4] << 8) | buf[3];
169 r->align = buf[5];
170 r->length = buf[6];
171
172 #ifdef DEBUG_ISAPNP
173 isapnp_print_io("", r);
174 #endif
175 break;
176
177 case ISAPNP_TAG_FIXED_IO_PORT_DESC:
178 r = &pa->ipa_io[pa->ipa_nio++];
179 r->flags = 0;
180 r->minbase = (buf[2] << 8) | buf[1];
181 r->maxbase = r->minbase;
182 r->align = 1;
183 r->length = buf[3];
184
185 #ifdef DEBUG_ISAPNP
186 isapnp_print_io("FIXED", r);
187 #endif
188 break;
189
190 case ISAPNP_TAG_RESERVED1:
191 case ISAPNP_TAG_RESERVED2:
192 case ISAPNP_TAG_RESERVED3:
193 case ISAPNP_TAG_RESERVED4:
194 break;
195
196 case ISAPNP_TAG_VENDOR_DEF:
197 break;
198
199 case ISAPNP_TAG_END:
200 break;
201
202 case ISAPNP_TAG_MEM_RANGE_DESC:
203 r = &pa->ipa_mem[pa->ipa_nmem++];
204 r->minbase = (buf[2] << 8) | buf[1];
205 r->maxbase = (buf[4] << 8) | buf[3];
206 r->align = (buf[6] << 8) | buf[5];
207 r->length = (buf[8] << 8) | buf[7];
208 #ifdef DEBUG_ISAPNP
209 isapnp_print_mem("16 bit", r);
210 #endif
211 break;
212
213 case ISAPNP_TAG_ANSI_IDENT_STRING:
214 buf[len] = '\0';
215 DPRINTF(("ANSI Ident: %s\n", buf));
216 if (pa->ipa_devident[0] == '\0')
217 COPY(pa->ipa_devident, buf);
218 else
219 COPY(pa->ipa_devclass, buf);
220 break;
221
222 case ISAPNP_TAG_UNICODE_IDENT_STRING:
223 buf[len] = '\0';
224 DPRINTF(("Unicode Ident: %s\n", buf));
225 break;
226
227 case ISAPNP_TAG_VENDOR_DEFINED:
228 break;
229
230 case ISAPNP_TAG_MEM32_RANGE_DESC:
231 r = &pa->ipa_mem32[pa->ipa_nmem32++];
232 r->flags = buf[0];
233 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
234 (buf[2] << 8) | buf[1];
235 r->maxbase = (buf[8] << 24) | (buf[7] << 16) |
236 (buf[6] << 8) | buf[5];
237 r->align = (buf[12] << 24) | (buf[11] << 16) |
238 (buf[10] << 8) | buf[9];
239 r->length = (buf[16] << 24) | (buf[15] << 16) |
240 (buf[14] << 8) | buf[13];
241 #ifdef DEBUG_ISAPNP
242 isapnp_print_mem("32 bit", r);
243 #endif
244 break;
245
246 case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC:
247 r = &pa->ipa_mem32[pa->ipa_nmem32++];
248 r->flags = buf[0];
249 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
250 (buf[2] << 8) | buf[1];
251 r->maxbase = r->minbase;
252 r->align = 1;
253 r->length = (buf[8] << 24) | (buf[7] << 16) |
254 (buf[6] << 8) | buf[5];
255 #ifdef DEBUG_ISAPNP
256 isapnp_print_mem("FIXED 32 bit", r);
257 #endif
258 break;
259
260 default:
261 #ifdef DEBUG_ISAPNP
262 {
263 int i;
264 printf("tag %.2x, len %d: ", tag, len);
265 for (i = 0; i < len; i++)
266 printf("%.2x ", buf[i]);
267 printf("\n");
268 }
269 #endif
270 break;
271 }
272 return pa;
273 }
274
275
276 /* isapnp_get_resource():
277 * Read the resources for card c
278 */
279 struct isapnp_attach_args *
280 isapnp_get_resource(sc, c)
281 struct isapnp_softc *sc;
282 int c;
283 {
284 u_char d, tag;
285 u_short len;
286 int i;
287 struct isapnp_attach_args *ipa, *pa;
288
289 pa = ipa = ISAPNP_MALLOC(sizeof(*ipa));
290 memset(ipa, 0, sizeof(*ipa));
291 pa->ipa_pref = ISAPNP_DEP_UNSET;
292
293 for (i = 0; i < ISAPNP_SERIAL_SIZE; i++) {
294 if (isapnp_wait_status(sc))
295 goto bad;
296
297 d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA);
298
299 if (d != sc->sc_id[c][i] && i != ISAPNP_SERIAL_SIZE - 1) {
300 printf("isapnp: card %d violates PnP spec; byte %d\n",
301 c + 1, i);
302 break;
303 }
304 }
305
306 do {
307 u_char buf[ISAPNP_MAX_TAGSIZE], *p;
308
309 memset(buf, 0, sizeof(buf));
310
311 #define NEXT_BYTE \
312 if (isapnp_wait_status(sc)) \
313 goto bad; \
314 d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA);
315
316 NEXT_BYTE;
317
318 if (d & ISAPNP_LARGE_TAG) {
319 tag = d;
320 NEXT_BYTE;
321 buf[0] = d;
322 NEXT_BYTE;
323 buf[1] = d;
324 len = (buf[1] << 8) | buf[0];
325 }
326 else {
327 tag = (d >> 3) & 0xf;
328 len = d & 0x7;
329 }
330
331 for (p = buf, i = 0; i < len; i++) {
332 NEXT_BYTE;
333 if (i < ISAPNP_MAX_TAGSIZE)
334 *p++ = d;
335 }
336
337 if (len >= ISAPNP_MAX_TAGSIZE) {
338 printf("isapnp: Maximum tag size exceeded, card %d\n",
339 c + 1);
340 len = ISAPNP_MAX_TAGSIZE;
341 }
342
343 pa = isapnp_process_tag(tag, len, buf, pa);
344 }
345 while (tag != ISAPNP_TAG_END);
346 return ipa;
347 bad:
348 while (ipa) {
349 pa = ipa->ipa_next;
350 ISAPNP_FREE(ipa);
351 ipa = pa;
352 }
353 printf("isapnp: Resource timeout, card %d\n", c + 1);
354 return NULL;
355 }
356