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