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