isapnpres.c revision 1.9 1 /* $NetBSD: isapnpres.c,v 1.9 1998/09/05 14:15:26 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Resource parser for Plug and Play cards.
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
47
48 #include <machine/bus.h>
49
50 #include <dev/isa/isavar.h>
51
52 #include <dev/isapnp/isapnpreg.h>
53 #include <dev/isapnp/isapnpvar.h>
54
55
56 static int isapnp_wait_status __P((struct isapnp_softc *));
57 static struct isapnp_attach_args *
58 isapnp_newdev __P((struct isapnp_attach_args *));
59 static struct isapnp_attach_args *
60 isapnp_newconf __P((struct isapnp_attach_args *));
61 static void isapnp_merge __P((struct isapnp_attach_args *,
62 const struct isapnp_attach_args *));
63 static struct isapnp_attach_args *
64 isapnp_flatten __P((struct isapnp_attach_args *));
65 static int isapnp_process_tag __P((u_char, u_char, u_char *,
66 struct isapnp_attach_args **, struct isapnp_attach_args **,
67 struct isapnp_attach_args **));
68
69
70 /* isapnp_wait_status():
71 * Wait for the next byte of resource data to become available
72 */
73 static int
74 isapnp_wait_status(sc)
75 struct isapnp_softc *sc;
76 {
77 int i;
78
79 /* wait up to 1 ms for each resource byte */
80 for (i = 0; i < 10; i++) {
81 if (isapnp_read_reg(sc, ISAPNP_STATUS) & 1)
82 return 0;
83 DELAY(100);
84 }
85 return 1;
86 }
87
88
89 /* isapnp_newdev():
90 * Add a new logical device to the current card; expand the configuration
91 * resources of the current card if needed.
92 */
93 static struct isapnp_attach_args *
94 isapnp_newdev(card)
95 struct isapnp_attach_args *card;
96 {
97 struct isapnp_attach_args *ipa, *dev = ISAPNP_MALLOC(sizeof(*dev));
98
99 memset(dev, 0, sizeof(*dev));
100
101 dev->ipa_pref = ISAPNP_DEP_ACCEPTABLE;
102 memcpy(dev->ipa_devident, card->ipa_devident,
103 sizeof(card->ipa_devident));
104
105 if (card->ipa_child == NULL)
106 card->ipa_child = dev;
107 else {
108 for (ipa = card->ipa_child; ipa->ipa_sibling != NULL;
109 ipa = ipa->ipa_sibling)
110 continue;
111 ipa->ipa_sibling = dev;
112 }
113
114
115 return dev;
116 }
117
118
119 /* isapnp_newconf():
120 * Add a new alternate configuration to a logical device
121 */
122 static struct isapnp_attach_args *
123 isapnp_newconf(dev)
124 struct isapnp_attach_args *dev;
125 {
126 struct isapnp_attach_args *ipa, *conf = ISAPNP_MALLOC(sizeof(*conf));
127
128 memset(conf, 0, sizeof(*conf));
129
130 memcpy(conf->ipa_devident, dev->ipa_devident,
131 sizeof(conf->ipa_devident));
132 memcpy(conf->ipa_devlogic, dev->ipa_devlogic,
133 sizeof(conf->ipa_devlogic));
134 memcpy(conf->ipa_devcompat, dev->ipa_devcompat,
135 sizeof(conf->ipa_devcompat));
136 memcpy(conf->ipa_devclass, dev->ipa_devclass,
137 sizeof(conf->ipa_devclass));
138
139 if (dev->ipa_child == NULL)
140 dev->ipa_child = conf;
141 else {
142 for (ipa = dev->ipa_child; ipa->ipa_sibling;
143 ipa = ipa->ipa_sibling)
144 continue;
145 ipa->ipa_sibling = conf;
146 }
147
148 return conf;
149 }
150
151
152 /* isapnp_merge():
153 * Merge the common device configurations to the subconfigurations
154 */
155 static void
156 isapnp_merge(c, d)
157 struct isapnp_attach_args *c;
158 const struct isapnp_attach_args *d;
159 {
160 int i;
161
162 for (i = 0; i < d->ipa_nio; i++)
163 c->ipa_io[c->ipa_nio++] = d->ipa_io[i];
164
165 for (i = 0; i < d->ipa_nmem; i++)
166 c->ipa_mem[c->ipa_nmem++] = d->ipa_mem[i];
167
168 for (i = 0; i < d->ipa_nmem32; i++)
169 c->ipa_mem32[c->ipa_nmem32++] = d->ipa_mem32[i];
170
171 for (i = 0; i < d->ipa_nirq; i++)
172 c->ipa_irq[c->ipa_nirq++] = d->ipa_irq[i];
173
174 for (i = 0; i < d->ipa_ndrq; i++)
175 c->ipa_drq[c->ipa_ndrq++] = d->ipa_drq[i];
176 }
177
178
179 /* isapnp_flatten():
180 * Flatten the tree to a list of config entries.
181 */
182 static struct isapnp_attach_args *
183 isapnp_flatten(card)
184 struct isapnp_attach_args *card;
185 {
186 struct isapnp_attach_args *dev, *conf, *d, *c, *pa;
187
188 dev = card->ipa_child;
189 ISAPNP_FREE(card);
190
191 for (conf = c = NULL, d = dev; d; d = dev) {
192 dev = d->ipa_sibling;
193 if (d->ipa_child == NULL) {
194 /*
195 * No subconfigurations; all configuration info
196 * is in the device node.
197 */
198 d->ipa_sibling = NULL;
199 pa = d;
200 }
201 else {
202 /*
203 * Push down device configuration info to the
204 * subconfigurations
205 */
206 for (pa = d->ipa_child; pa; pa = pa->ipa_sibling)
207 isapnp_merge(pa, d);
208
209 pa = d->ipa_child;
210 ISAPNP_FREE(d);
211 }
212
213 if (c == NULL)
214 c = conf = pa;
215 else
216 c->ipa_sibling = pa;
217
218 while (c->ipa_sibling)
219 c = c->ipa_sibling;
220 }
221 return conf;
222 }
223
224
225 /* isapnp_process_tag():
226 * Process a resource tag
227 */
228 static int
229 isapnp_process_tag(tag, len, buf, card, dev, conf)
230 u_char tag, len, *buf;
231 struct isapnp_attach_args **card, **dev, **conf;
232 {
233 char str[64];
234 struct isapnp_region *r;
235 struct isapnp_pin *p;
236 struct isapnp_attach_args *pa;
237
238 #define COPY(a, b) strncpy((a), (b), sizeof(a)), (a)[sizeof(a) - 1] = '\0'
239
240 switch (tag) {
241 case ISAPNP_TAG_VERSION_NUM:
242 DPRINTF(("PnP version %d.%d, Vendor version %d.%d\n",
243 buf[0] >> 4, buf[0] & 0xf, buf[1] >> 4, buf[1] & 0xf));
244 return 0;
245
246 case ISAPNP_TAG_LOGICAL_DEV_ID:
247 (void) isapnp_id_to_vendor(str, buf);
248 DPRINTF(("Logical device id %s\n", str));
249
250 *dev = isapnp_newdev(*card);
251 COPY((*dev)->ipa_devlogic, str);
252 return 0;
253
254 case ISAPNP_TAG_COMPAT_DEV_ID:
255 (void) isapnp_id_to_vendor(str, buf);
256 DPRINTF(("Compatible device id %s\n", str));
257
258 if (*dev == NULL)
259 return -1;
260
261 if (*(*dev)->ipa_devcompat == '\0')
262 COPY((*dev)->ipa_devcompat, str);
263 return 0;
264
265 case ISAPNP_TAG_DEP_START:
266 if (len == 0)
267 buf[0] = ISAPNP_DEP_ACCEPTABLE;
268
269 if (*dev == NULL)
270 return -1;
271
272 *conf = isapnp_newconf(*dev);
273 (*conf)->ipa_pref = buf[0];
274 #ifdef DEBUG_ISAPNP
275 isapnp_print_dep_start(">>> Start dependent function ",
276 (*conf)->ipa_pref);
277 #endif
278 return 0;
279
280 case ISAPNP_TAG_DEP_END:
281 DPRINTF(("<<<End dependent functions\n"));
282 *conf = NULL;
283 return 0;
284
285 case ISAPNP_TAG_ANSI_IDENT_STRING:
286 buf[len] = '\0';
287 DPRINTF(("ANSI Ident: %s\n", buf));
288 if (*dev == NULL)
289 COPY((*card)->ipa_devident, buf);
290 else
291 COPY((*dev)->ipa_devclass, buf);
292 return 0;
293
294 case ISAPNP_TAG_END:
295 *dev = NULL;
296 return 0;
297
298 default:
299 /* Handled below */
300 break;
301 }
302
303
304 /*
305 * Decide which configuration we add the tag to
306 */
307 if (*conf)
308 pa = *conf;
309 else if (*dev)
310 pa = *dev;
311 else
312 /* error */
313 return -1;
314
315 switch (tag) {
316 case ISAPNP_TAG_IRQ_FORMAT:
317 if (len < 2)
318 break;
319
320 if (len != 3)
321 buf[2] = ISAPNP_IRQTYPE_EDGE_PLUS;
322
323 p = &pa->ipa_irq[pa->ipa_nirq++];
324 p->bits = buf[0] | (buf[1] << 8);
325 p->flags = buf[2];
326 #ifdef DEBUG_ISAPNP
327 isapnp_print_irq("", p);
328 #endif
329 break;
330
331 case ISAPNP_TAG_DMA_FORMAT:
332 if (buf[0] == 0)
333 break;
334
335 p = &pa->ipa_drq[pa->ipa_ndrq++];
336 p->bits = buf[0];
337 p->flags = buf[1];
338 #ifdef DEBUG_ISAPNP
339 isapnp_print_drq("", p);
340 #endif
341 break;
342
343
344 case ISAPNP_TAG_IO_PORT_DESC:
345 r = &pa->ipa_io[pa->ipa_nio++];
346 r->flags = buf[0];
347 r->minbase = (buf[2] << 8) | buf[1];
348 r->maxbase = (buf[4] << 8) | buf[3];
349 r->align = buf[5];
350 r->length = buf[6];
351 #ifdef DEBUG_ISAPNP
352 isapnp_print_io("", r);
353 #endif
354 break;
355
356 case ISAPNP_TAG_FIXED_IO_PORT_DESC:
357 r = &pa->ipa_io[pa->ipa_nio++];
358 r->flags = 0;
359 r->minbase = (buf[1] << 8) | buf[0];
360 r->maxbase = r->minbase;
361 r->align = 1;
362 r->length = buf[2];
363 #ifdef DEBUG_ISAPNP
364 isapnp_print_io("FIXED ", r);
365 #endif
366 break;
367
368 case ISAPNP_TAG_VENDOR_DEF:
369 DPRINTF(("Vendor defined (short)\n"));
370 break;
371
372 case ISAPNP_TAG_MEM_RANGE_DESC:
373 r = &pa->ipa_mem[pa->ipa_nmem++];
374 r->flags = buf[0];
375 r->minbase = (buf[2] << 16) | (buf[1] << 8);
376 r->maxbase = (buf[4] << 16) | (buf[3] << 8);
377 r->align = (buf[6] << 8) | buf[5];
378 r->length = (buf[8] << 16) | (buf[7] << 8);
379 #ifdef DEBUG_ISAPNP
380 isapnp_print_mem("", r);
381 #endif
382 break;
383
384
385 case ISAPNP_TAG_UNICODE_IDENT_STRING:
386 DPRINTF(("Unicode Ident\n"));
387 break;
388
389 case ISAPNP_TAG_VENDOR_DEFINED:
390 DPRINTF(("Vendor defined (long)\n"));
391 break;
392
393 case ISAPNP_TAG_MEM32_RANGE_DESC:
394 r = &pa->ipa_mem32[pa->ipa_nmem32++];
395 r->flags = buf[0];
396 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
397 (buf[2] << 8) | buf[1];
398 r->maxbase = (buf[8] << 24) | (buf[7] << 16) |
399 (buf[6] << 8) | buf[5];
400 r->align = (buf[12] << 24) | (buf[11] << 16) |
401 (buf[10] << 8) | buf[9];
402 r->length = (buf[16] << 24) | (buf[15] << 16) |
403 (buf[14] << 8) | buf[13];
404 #ifdef DEBUG_ISAPNP
405 isapnp_print_mem("32-bit ", r);
406 #endif
407 break;
408
409 case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC:
410 r = &pa->ipa_mem32[pa->ipa_nmem32++];
411 r->flags = buf[0];
412 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
413 (buf[2] << 8) | buf[1];
414 r->maxbase = r->minbase;
415 r->align = 1;
416 r->length = (buf[8] << 24) | (buf[7] << 16) |
417 (buf[6] << 8) | buf[5];
418 #ifdef DEBUG_ISAPNP
419 isapnp_print_mem("FIXED 32-bit ", r);
420 #endif
421 break;
422
423 default:
424 #ifdef DEBUG_ISAPNP
425 {
426 int i;
427 printf("tag %.2x, len %d: ", tag, len);
428 for (i = 0; i < len; i++)
429 printf("%.2x ", buf[i]);
430 printf("\n");
431 }
432 #endif
433 break;
434 }
435 return 0;
436 }
437
438
439 /* isapnp_get_resource():
440 * Read the resources for card c
441 */
442 struct isapnp_attach_args *
443 isapnp_get_resource(sc, c)
444 struct isapnp_softc *sc;
445 int c;
446 {
447 u_char d, tag;
448 u_short len;
449 int i;
450 int warned = 0;
451 struct isapnp_attach_args *card, *dev = NULL, *conf = NULL;
452 u_char buf[ISAPNP_MAX_TAGSIZE], *p;
453
454 memset(buf, 0, sizeof(buf));
455
456 card = ISAPNP_MALLOC(sizeof(*card));
457 memset(card, 0, sizeof(*card));
458
459 #define NEXT_BYTE \
460 if (isapnp_wait_status(sc)) \
461 goto bad; \
462 d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA)
463
464 for (i = 0; i < ISAPNP_SERIAL_SIZE; i++) {
465 NEXT_BYTE;
466
467 if (d != sc->sc_id[c][i] && i != ISAPNP_SERIAL_SIZE - 1) {
468 if (!warned) {
469 printf("%s: card %d violates PnP spec; byte %d\n",
470 sc->sc_dev.dv_xname, c + 1, i);
471 warned++;
472 }
473 if (i == 0) {
474 /*
475 * Magic! If this is the first byte, we
476 * assume that the tag data begins here.
477 */
478 goto parse;
479 }
480 }
481 }
482
483 do {
484 NEXT_BYTE;
485 parse:
486
487 if (d & ISAPNP_LARGE_TAG) {
488 tag = d;
489 NEXT_BYTE;
490 buf[0] = d;
491 NEXT_BYTE;
492 buf[1] = d;
493 len = (buf[1] << 8) | buf[0];
494 }
495 else {
496 tag = (d >> 3) & 0xf;
497 len = d & 0x7;
498 }
499
500 for (p = buf, i = 0; i < len; i++) {
501 NEXT_BYTE;
502 if (i < ISAPNP_MAX_TAGSIZE)
503 *p++ = d;
504 }
505
506 if (len >= ISAPNP_MAX_TAGSIZE) {
507 printf("%s: Maximum tag size exceeded, card %d\n",
508 sc->sc_dev.dv_xname, c + 1);
509 len = ISAPNP_MAX_TAGSIZE;
510 if (++warned == 10)
511 goto bad;
512 }
513
514 if (isapnp_process_tag(tag, len, buf, &card, &dev, &conf) == -1)
515 printf("%s: No current device for tag, card %d\n",
516 sc->sc_dev.dv_xname, c + 1);
517 }
518 while (tag != ISAPNP_TAG_END);
519 return isapnp_flatten(card);
520
521 bad:
522 for (card = isapnp_flatten(card); card; ) {
523 dev = card->ipa_sibling;
524 ISAPNP_FREE(card);
525 card = dev;
526 }
527 printf("%s: %s, card %d\n", sc->sc_dev.dv_xname,
528 warned >= 10 ? "Too many tag errors" : "Resource timeout", c + 1);
529 return NULL;
530 }
531