isapnpres.c revision 1.5 1 /* $NetBSD: isapnpres.c,v 1.5 1997/01/24 22:13:10 christos 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 *
51 isapnp_newdev __P((struct isapnp_attach_args *));
52 static struct isapnp_attach_args *
53 isapnp_newconf __P((struct isapnp_attach_args *));
54 static void isapnp_merge __P((struct isapnp_attach_args *,
55 const struct isapnp_attach_args *));
56 static struct isapnp_attach_args *
57 isapnp_flatten __P((struct isapnp_attach_args *));
58 static int isapnp_process_tag __P((u_char, u_char, u_char *,
59 struct isapnp_attach_args **, struct isapnp_attach_args **,
60 struct isapnp_attach_args **));
61
62
63 /* isapnp_wait_status():
64 * Wait for the next byte of resource data to become available
65 */
66 static int
67 isapnp_wait_status(sc)
68 struct isapnp_softc *sc;
69 {
70 int i;
71
72 for (i = 0; i < 10; i++) {
73 if (isapnp_read_reg(sc, ISAPNP_STATUS) & 1)
74 return 0;
75 DELAY(40);
76 }
77 return 1;
78 }
79
80
81 /* isapnp_newdev():
82 * Add a new logical device to the current card; expand the configuration
83 * resources of the current card if needed.
84 */
85 static struct isapnp_attach_args *
86 isapnp_newdev(card)
87 struct isapnp_attach_args *card;
88 {
89 struct isapnp_attach_args *ipa, *dev = ISAPNP_MALLOC(sizeof(*dev));
90
91 memset(dev, 0, sizeof(*dev));
92
93 dev->ipa_pref = ISAPNP_DEP_ACCEPTABLE;
94 memcpy(dev->ipa_devident, card->ipa_devident,
95 sizeof(card->ipa_devident));
96
97 if (card->ipa_child == NULL)
98 card->ipa_child = dev;
99 else {
100 for (ipa = card->ipa_child; ipa->ipa_sibling != NULL;
101 ipa = ipa->ipa_sibling)
102 continue;
103 ipa->ipa_sibling = dev;
104 }
105
106
107 return dev;
108 }
109
110
111 /* isapnp_newconf():
112 * Add a new alternate configuration to a logical device
113 */
114 static struct isapnp_attach_args *
115 isapnp_newconf(dev)
116 struct isapnp_attach_args *dev;
117 {
118 struct isapnp_attach_args *ipa, *conf = ISAPNP_MALLOC(sizeof(*conf));
119
120 memset(conf, 0, sizeof(*conf));
121
122 memcpy(conf->ipa_devident, dev->ipa_devident,
123 sizeof(conf->ipa_devident));
124 memcpy(conf->ipa_devlogic, dev->ipa_devlogic,
125 sizeof(conf->ipa_devlogic));
126 memcpy(conf->ipa_devclass, dev->ipa_devclass,
127 sizeof(conf->ipa_devclass));
128
129 if (dev->ipa_child == NULL)
130 dev->ipa_child = conf;
131 else {
132 for (ipa = dev->ipa_child; ipa->ipa_sibling;
133 ipa = ipa->ipa_sibling)
134 continue;
135 ipa->ipa_sibling = conf;
136 }
137
138 return conf;
139 }
140
141
142 /* isapnp_merge():
143 * Merge the common device configurations to the subconfigurations
144 */
145 static void
146 isapnp_merge(c, d)
147 struct isapnp_attach_args *c;
148 const struct isapnp_attach_args *d;
149 {
150 int i;
151
152 for (i = 0; i < d->ipa_nio; i++)
153 c->ipa_io[c->ipa_nio++] = d->ipa_io[i];
154
155 for (i = 0; i < d->ipa_nmem; i++)
156 c->ipa_mem[c->ipa_nmem++] = d->ipa_mem[i];
157
158 for (i = 0; i < d->ipa_nmem32; i++)
159 c->ipa_mem32[c->ipa_nmem32++] = d->ipa_mem32[i];
160
161 for (i = 0; i < d->ipa_nirq; i++)
162 c->ipa_irq[c->ipa_nirq++] = d->ipa_irq[i];
163
164 for (i = 0; i < d->ipa_ndrq; i++)
165 c->ipa_drq[c->ipa_ndrq++] = d->ipa_drq[i];
166 }
167
168
169 /* isapnp_flatten():
170 * Flatten the tree to a list of config entries.
171 */
172 static struct isapnp_attach_args *
173 isapnp_flatten(card)
174 struct isapnp_attach_args *card;
175 {
176 struct isapnp_attach_args *dev, *conf, *d, *c, *pa;
177
178 dev = card->ipa_child;
179 ISAPNP_FREE(card);
180
181 for (conf = c = NULL, d = dev; d; d = dev) {
182 dev = d->ipa_sibling;
183 if (d->ipa_child == NULL) {
184 /*
185 * No subconfigurations; all configuration info
186 * is in the device node.
187 */
188 d->ipa_sibling = NULL;
189 pa = d;
190 }
191 else {
192 /*
193 * Push down device configuration info to the
194 * subconfigurations
195 */
196 for (pa = d->ipa_child; pa; pa = pa->ipa_sibling)
197 isapnp_merge(pa, d);
198
199 pa = d->ipa_child;
200 ISAPNP_FREE(d);
201 }
202
203 if (c == NULL)
204 c = conf = pa;
205 else
206 c->ipa_sibling = pa;
207
208 while (c->ipa_sibling)
209 c = c->ipa_sibling;
210 }
211 return conf;
212 }
213
214
215 /* isapnp_process_tag():
216 * Process a resource tag
217 */
218 static int
219 isapnp_process_tag(tag, len, buf, card, dev, conf)
220 u_char tag, len, *buf;
221 struct isapnp_attach_args **card, **dev, **conf;
222 {
223 char str[64];
224 struct isapnp_region *r;
225 struct isapnp_pin *p;
226 struct isapnp_attach_args *pa;
227
228 #define COPY(a, b) strncpy((a), (b), sizeof(a)), (a)[sizeof(a) - 1] = '\0'
229
230 switch (tag) {
231 case ISAPNP_TAG_VERSION_NUM:
232 DPRINTF(("PnP version %d.%d, Vendor version %d.%d\n",
233 buf[0] >> 4, buf[0] & 0xf, buf[1] >> 4, buf[1] & 0xf));
234 return 0;
235
236 case ISAPNP_TAG_LOGICAL_DEV_ID:
237 (void) isapnp_id_to_vendor(str, buf);
238 DPRINTF(("Logical device id %s\n", str));
239
240 *dev = isapnp_newdev(*card);
241 COPY((*dev)->ipa_devlogic, str);
242 return 0;
243
244 case ISAPNP_TAG_COMPAT_DEV_ID:
245 (void) isapnp_id_to_vendor(str, buf);
246 DPRINTF(("Compatible device id %s\n", str));
247 return 0;
248
249 case ISAPNP_TAG_DEP_START:
250 if (len == 0)
251 buf[0] = ISAPNP_DEP_ACCEPTABLE;
252
253 if (*dev == NULL)
254 return -1;
255
256 *conf = isapnp_newconf(*dev);
257 (*conf)->ipa_pref = buf[0];
258 #ifdef DEBUG_ISAPNP
259 isapnp_print_dep_start(">>> Start dependent functions ",
260 (*conf)->ipa_pref);
261 #endif
262 return 0;
263
264 case ISAPNP_TAG_DEP_END:
265 DPRINTF(("<<<End dependend functions\n"));
266 *conf = NULL;
267 return 0;
268
269 case ISAPNP_TAG_ANSI_IDENT_STRING:
270 buf[len] = '\0';
271 DPRINTF(("ANSI Ident: %s\n", buf));
272 if (*dev == NULL)
273 COPY((*card)->ipa_devident, buf);
274 else
275 COPY((*dev)->ipa_devclass, buf);
276 return 0;
277
278 case ISAPNP_TAG_END:
279 *dev = NULL;
280 return 0;
281
282 default:
283 /* Handled below */
284 break;
285 }
286
287
288 /*
289 * Decide which configuration we add the tag to
290 */
291 if (*conf)
292 pa = *conf;
293 else if (*dev)
294 pa = *dev;
295 else
296 /* error */
297 return -1;
298
299 switch (tag) {
300 case ISAPNP_TAG_IRQ_FORMAT:
301 if (len < 2)
302 break;
303
304 if (len != 3)
305 buf[2] = ISAPNP_IRQTYPE_EDGE_PLUS;
306
307 p = &pa->ipa_irq[pa->ipa_nirq++];
308 p->bits = buf[0] | (buf[1] << 8);
309 p->flags = buf[2];
310 #ifdef DEBUG_ISAPNP
311 isapnp_print_irq("", p);
312 #endif
313 break;
314
315 case ISAPNP_TAG_DMA_FORMAT:
316 if (buf[0] == 0)
317 break;
318
319 p = &pa->ipa_drq[pa->ipa_ndrq++];
320 p->bits = buf[0];
321 p->flags = buf[1];
322 #ifdef DEBUG_ISAPNP
323 isapnp_print_drq("", p);
324 #endif
325 break;
326
327
328 case ISAPNP_TAG_IO_PORT_DESC:
329 r = &pa->ipa_io[pa->ipa_nio++];
330 r->flags = buf[0];
331 r->minbase = (buf[2] << 8) | buf[1];
332 r->maxbase = (buf[4] << 8) | buf[3];
333 r->align = buf[5];
334 r->length = buf[6];
335
336 #ifdef DEBUG_ISAPNP
337 isapnp_print_io("", r);
338 #endif
339 break;
340
341 case ISAPNP_TAG_FIXED_IO_PORT_DESC:
342 r = &pa->ipa_io[pa->ipa_nio++];
343 r->flags = 0;
344 r->minbase = (buf[2] << 8) | buf[1];
345 r->maxbase = r->minbase;
346 r->align = 1;
347 r->length = buf[3];
348
349 #ifdef DEBUG_ISAPNP
350 isapnp_print_io("FIXED", r);
351 #endif
352 break;
353
354 case ISAPNP_TAG_RESERVED1:
355 case ISAPNP_TAG_RESERVED2:
356 case ISAPNP_TAG_RESERVED3:
357 case ISAPNP_TAG_RESERVED4:
358 break;
359
360 case ISAPNP_TAG_VENDOR_DEF:
361 break;
362
363 case ISAPNP_TAG_MEM_RANGE_DESC:
364 r = &pa->ipa_mem[pa->ipa_nmem++];
365 r->minbase = (buf[2] << 8) | buf[1];
366 r->maxbase = (buf[4] << 8) | buf[3];
367 r->align = (buf[6] << 8) | buf[5];
368 r->length = (buf[8] << 8) | buf[7];
369 #ifdef DEBUG_ISAPNP
370 isapnp_print_mem("16 bit", r);
371 #endif
372 break;
373
374
375 case ISAPNP_TAG_UNICODE_IDENT_STRING:
376 buf[len] = '\0';
377 DPRINTF(("Unicode Ident: %s\n", buf));
378 break;
379
380 case ISAPNP_TAG_VENDOR_DEFINED:
381 break;
382
383 case ISAPNP_TAG_MEM32_RANGE_DESC:
384 r = &pa->ipa_mem32[pa->ipa_nmem32++];
385 r->flags = buf[0];
386 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
387 (buf[2] << 8) | buf[1];
388 r->maxbase = (buf[8] << 24) | (buf[7] << 16) |
389 (buf[6] << 8) | buf[5];
390 r->align = (buf[12] << 24) | (buf[11] << 16) |
391 (buf[10] << 8) | buf[9];
392 r->length = (buf[16] << 24) | (buf[15] << 16) |
393 (buf[14] << 8) | buf[13];
394 #ifdef DEBUG_ISAPNP
395 isapnp_print_mem("32 bit", r);
396 #endif
397 break;
398
399 case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC:
400 r = &pa->ipa_mem32[pa->ipa_nmem32++];
401 r->flags = buf[0];
402 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
403 (buf[2] << 8) | buf[1];
404 r->maxbase = r->minbase;
405 r->align = 1;
406 r->length = (buf[8] << 24) | (buf[7] << 16) |
407 (buf[6] << 8) | buf[5];
408 #ifdef DEBUG_ISAPNP
409 isapnp_print_mem("FIXED 32 bit", r);
410 #endif
411 break;
412
413 default:
414 #ifdef DEBUG_ISAPNP
415 {
416 int i;
417 printf("tag %.2x, len %d: ", tag, len);
418 for (i = 0; i < len; i++)
419 printf("%.2x ", buf[i]);
420 printf("\n");
421 }
422 #endif
423 break;
424 }
425 return 0;
426 }
427
428
429 /* isapnp_get_resource():
430 * Read the resources for card c
431 */
432 struct isapnp_attach_args *
433 isapnp_get_resource(sc, c)
434 struct isapnp_softc *sc;
435 int c;
436 {
437 u_char d, tag;
438 u_short len;
439 int i;
440 int warned = 0;
441 struct isapnp_attach_args *card, *dev = NULL, *conf = NULL;
442 u_char buf[ISAPNP_MAX_TAGSIZE], *p;
443
444 memset(buf, 0, sizeof(buf));
445
446 card = ISAPNP_MALLOC(sizeof(*card));
447 memset(card, 0, sizeof(*card));
448
449 #define NEXT_BYTE \
450 if (isapnp_wait_status(sc)) \
451 goto bad; \
452 d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA)
453
454 for (i = 0; i < ISAPNP_SERIAL_SIZE; i++) {
455 NEXT_BYTE;
456
457 if (d != sc->sc_id[c][i] && i != ISAPNP_SERIAL_SIZE - 1) {
458 if (!warned) {
459 printf("%s: card %d violates PnP spec; byte %d\n",
460 sc->sc_dev.dv_xname, c + 1, i);
461 warned++;
462 }
463 if (i == 0) {
464 /*
465 * Magic! If this is the first byte, we
466 * assume that the tag data begins here.
467 */
468 goto parse;
469 }
470 }
471 }
472
473 do {
474 NEXT_BYTE;
475 parse:
476
477 if (d & ISAPNP_LARGE_TAG) {
478 tag = d;
479 NEXT_BYTE;
480 buf[0] = d;
481 NEXT_BYTE;
482 buf[1] = d;
483 len = (buf[1] << 8) | buf[0];
484 }
485 else {
486 tag = (d >> 3) & 0xf;
487 len = d & 0x7;
488 }
489
490 for (p = buf, i = 0; i < len; i++) {
491 NEXT_BYTE;
492 if (i < ISAPNP_MAX_TAGSIZE)
493 *p++ = d;
494 }
495
496 if (len >= ISAPNP_MAX_TAGSIZE) {
497 printf("%s: Maximum tag size exceeded, card %d\n",
498 sc->sc_dev.dv_xname, c + 1);
499 len = ISAPNP_MAX_TAGSIZE;
500 if (++warned == 10)
501 goto bad;
502 }
503
504 if (isapnp_process_tag(tag, len, buf, &card, &dev, &conf) == -1)
505 printf("%s: No current device for tag, card %d\n",
506 sc->sc_dev.dv_xname, c + 1);
507 }
508 while (tag != ISAPNP_TAG_END);
509 return isapnp_flatten(card);
510
511 bad:
512 for (card = isapnp_flatten(card); card; ) {
513 dev = card->ipa_sibling;
514 ISAPNP_FREE(card);
515 card = dev;
516 }
517 printf("%s: %s, card %d\n", sc->sc_dev.dv_xname,
518 warned >= 10 ? "Too many tag errors" : "Resource timeout", c + 1);
519 return NULL;
520 }
521