isapnpres.c revision 1.10 1 /* $NetBSD: isapnpres.c,v 1.10 2000/05/23 17:50:53 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 if (r->length == 0)
352 pa->ipa_nio--;
353 #ifdef DEBUG_ISAPNP
354 isapnp_print_io("", r);
355 #endif
356 break;
357
358 case ISAPNP_TAG_FIXED_IO_PORT_DESC:
359 r = &pa->ipa_io[pa->ipa_nio++];
360 r->flags = 0;
361 r->minbase = (buf[1] << 8) | buf[0];
362 r->maxbase = r->minbase;
363 r->align = 1;
364 r->length = buf[2];
365 if (r->length == 0)
366 pa->ipa_nio--;
367 #ifdef DEBUG_ISAPNP
368 isapnp_print_io("FIXED ", r);
369 #endif
370 break;
371
372 case ISAPNP_TAG_VENDOR_DEF:
373 DPRINTF(("Vendor defined (short)\n"));
374 break;
375
376 case ISAPNP_TAG_MEM_RANGE_DESC:
377 r = &pa->ipa_mem[pa->ipa_nmem++];
378 r->flags = buf[0];
379 r->minbase = (buf[2] << 16) | (buf[1] << 8);
380 r->maxbase = (buf[4] << 16) | (buf[3] << 8);
381 r->align = (buf[6] << 8) | buf[5];
382 r->length = (buf[8] << 16) | (buf[7] << 8);
383 if (r->length == 0)
384 pa->ipa_nmem--;
385 #ifdef DEBUG_ISAPNP
386 isapnp_print_mem("", r);
387 #endif
388 break;
389
390
391 case ISAPNP_TAG_UNICODE_IDENT_STRING:
392 DPRINTF(("Unicode Ident\n"));
393 break;
394
395 case ISAPNP_TAG_VENDOR_DEFINED:
396 DPRINTF(("Vendor defined (long)\n"));
397 break;
398
399 case ISAPNP_TAG_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 = (buf[8] << 24) | (buf[7] << 16) |
405 (buf[6] << 8) | buf[5];
406 r->align = (buf[12] << 24) | (buf[11] << 16) |
407 (buf[10] << 8) | buf[9];
408 r->length = (buf[16] << 24) | (buf[15] << 16) |
409 (buf[14] << 8) | buf[13];
410 if (r->length == 0)
411 pa->ipa_nmem32--;
412 #ifdef DEBUG_ISAPNP
413 isapnp_print_mem("32-bit ", r);
414 #endif
415 break;
416
417 case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC:
418 r = &pa->ipa_mem32[pa->ipa_nmem32++];
419 r->flags = buf[0];
420 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
421 (buf[2] << 8) | buf[1];
422 r->maxbase = r->minbase;
423 r->align = 1;
424 r->length = (buf[8] << 24) | (buf[7] << 16) |
425 (buf[6] << 8) | buf[5];
426 if (r->length == 0)
427 pa->ipa_nmem32--;
428 #ifdef DEBUG_ISAPNP
429 isapnp_print_mem("FIXED 32-bit ", r);
430 #endif
431 break;
432
433 default:
434 #ifdef DEBUG_ISAPNP
435 {
436 int i;
437 printf("tag %.2x, len %d: ", tag, len);
438 for (i = 0; i < len; i++)
439 printf("%.2x ", buf[i]);
440 printf("\n");
441 }
442 #endif
443 break;
444 }
445 return 0;
446 }
447
448
449 /* isapnp_get_resource():
450 * Read the resources for card c
451 */
452 struct isapnp_attach_args *
453 isapnp_get_resource(sc, c)
454 struct isapnp_softc *sc;
455 int c;
456 {
457 u_char d, tag;
458 u_short len;
459 int i;
460 int warned = 0;
461 struct isapnp_attach_args *card, *dev = NULL, *conf = NULL;
462 u_char buf[ISAPNP_MAX_TAGSIZE], *p;
463
464 memset(buf, 0, sizeof(buf));
465
466 card = ISAPNP_MALLOC(sizeof(*card));
467 memset(card, 0, sizeof(*card));
468
469 #define NEXT_BYTE \
470 if (isapnp_wait_status(sc)) \
471 goto bad; \
472 d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA)
473
474 for (i = 0; i < ISAPNP_SERIAL_SIZE; i++) {
475 NEXT_BYTE;
476
477 if (d != sc->sc_id[c][i] && i != ISAPNP_SERIAL_SIZE - 1) {
478 if (!warned) {
479 printf("%s: card %d violates PnP spec; byte %d\n",
480 sc->sc_dev.dv_xname, c + 1, i);
481 warned++;
482 }
483 if (i == 0) {
484 /*
485 * Magic! If this is the first byte, we
486 * assume that the tag data begins here.
487 */
488 goto parse;
489 }
490 }
491 }
492
493 do {
494 NEXT_BYTE;
495 parse:
496
497 if (d & ISAPNP_LARGE_TAG) {
498 tag = d;
499 NEXT_BYTE;
500 buf[0] = d;
501 NEXT_BYTE;
502 buf[1] = d;
503 len = (buf[1] << 8) | buf[0];
504 }
505 else {
506 tag = (d >> 3) & 0xf;
507 len = d & 0x7;
508 }
509
510 for (p = buf, i = 0; i < len; i++) {
511 NEXT_BYTE;
512 if (i < ISAPNP_MAX_TAGSIZE)
513 *p++ = d;
514 }
515
516 if (len >= ISAPNP_MAX_TAGSIZE) {
517 printf("%s: Maximum tag size exceeded, card %d\n",
518 sc->sc_dev.dv_xname, c + 1);
519 len = ISAPNP_MAX_TAGSIZE;
520 if (++warned == 10)
521 goto bad;
522 }
523
524 if (isapnp_process_tag(tag, len, buf, &card, &dev, &conf) == -1)
525 printf("%s: No current device for tag, card %d\n",
526 sc->sc_dev.dv_xname, c + 1);
527 }
528 while (tag != ISAPNP_TAG_END);
529 return isapnp_flatten(card);
530
531 bad:
532 for (card = isapnp_flatten(card); card; ) {
533 dev = card->ipa_sibling;
534 ISAPNP_FREE(card);
535 card = dev;
536 }
537 printf("%s: %s, card %d\n", sc->sc_dev.dv_xname,
538 warned >= 10 ? "Too many tag errors" : "Resource timeout", c + 1);
539 return NULL;
540 }
541