1 /* $NetBSD: isapnpres.c,v 1.20 2009/03/14 15:36:18 dsl Exp $ */
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Resource parser for Plug and Play cards.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: isapnpres.c,v 1.20 2009/03/14 15:36:18 dsl Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
46 #include <dev/isa/isavar.h>
48 #include <dev/isapnp/isapnpreg.h>
49 #include <dev/isapnp/isapnpvar.h>
52 static int isapnp_wait_status(struct isapnp_softc
*);
53 static struct isapnp_attach_args
*
54 isapnp_newdev(struct isapnp_attach_args
*);
55 static struct isapnp_attach_args
*
56 isapnp_newconf(struct isapnp_attach_args
*);
57 static void isapnp_merge(struct isapnp_attach_args
*,
58 const struct isapnp_attach_args
*);
59 static struct isapnp_attach_args
*
60 isapnp_flatten(struct isapnp_attach_args
*);
61 static int isapnp_process_tag(u_char
, u_char
, u_char
*,
62 struct isapnp_attach_args
**, struct isapnp_attach_args
**,
63 struct isapnp_attach_args
**);
66 /* isapnp_wait_status():
67 * Wait for the next byte of resource data to become available
70 isapnp_wait_status(struct isapnp_softc
*sc
)
74 /* wait up to 1 ms for each resource byte */
75 for (i
= 0; i
< 10; i
++) {
76 if (isapnp_read_reg(sc
, ISAPNP_STATUS
) & 1)
85 * Add a new logical device to the current card; expand the configuration
86 * resources of the current card if needed.
88 static struct isapnp_attach_args
*
89 isapnp_newdev(struct isapnp_attach_args
*card
)
91 struct isapnp_attach_args
*ipa
, *dev
= ISAPNP_MALLOC(sizeof(*dev
));
93 memset(dev
, 0, sizeof(*dev
));
95 dev
->ipa_pref
= ISAPNP_DEP_ACCEPTABLE
;
96 memcpy(dev
->ipa_devident
, card
->ipa_devident
,
97 sizeof(card
->ipa_devident
));
99 if (card
->ipa_child
== NULL
)
100 card
->ipa_child
= dev
;
102 for (ipa
= card
->ipa_child
; ipa
->ipa_sibling
!= NULL
;
103 ipa
= ipa
->ipa_sibling
)
105 ipa
->ipa_sibling
= dev
;
114 * Add a new alternate configuration to a logical device
116 static struct isapnp_attach_args
*
117 isapnp_newconf(struct isapnp_attach_args
*dev
)
119 struct isapnp_attach_args
*ipa
, *conf
= ISAPNP_MALLOC(sizeof(*conf
));
121 memset(conf
, 0, sizeof(*conf
));
123 memcpy(conf
->ipa_devident
, dev
->ipa_devident
,
124 sizeof(conf
->ipa_devident
));
125 memcpy(conf
->ipa_devlogic
, dev
->ipa_devlogic
,
126 sizeof(conf
->ipa_devlogic
));
127 memcpy(conf
->ipa_devcompat
, dev
->ipa_devcompat
,
128 sizeof(conf
->ipa_devcompat
));
129 memcpy(conf
->ipa_devclass
, dev
->ipa_devclass
,
130 sizeof(conf
->ipa_devclass
));
132 if (dev
->ipa_child
== NULL
)
133 dev
->ipa_child
= conf
;
135 for (ipa
= dev
->ipa_child
; ipa
->ipa_sibling
;
136 ipa
= ipa
->ipa_sibling
)
138 ipa
->ipa_sibling
= conf
;
146 * Merge the common device configurations to the subconfigurations
149 isapnp_merge(struct isapnp_attach_args
*c
, const struct isapnp_attach_args
*d
)
153 for (i
= 0; i
< d
->ipa_nio
; i
++)
154 c
->ipa_io
[c
->ipa_nio
++] = d
->ipa_io
[i
];
156 for (i
= 0; i
< d
->ipa_nmem
; i
++)
157 c
->ipa_mem
[c
->ipa_nmem
++] = d
->ipa_mem
[i
];
159 for (i
= 0; i
< d
->ipa_nmem32
; i
++)
160 c
->ipa_mem32
[c
->ipa_nmem32
++] = d
->ipa_mem32
[i
];
162 for (i
= 0; i
< d
->ipa_nirq
; i
++)
163 c
->ipa_irq
[c
->ipa_nirq
++] = d
->ipa_irq
[i
];
165 for (i
= 0; i
< d
->ipa_ndrq
; i
++)
166 c
->ipa_drq
[c
->ipa_ndrq
++] = d
->ipa_drq
[i
];
171 * Flatten the tree to a list of config entries.
173 static struct isapnp_attach_args
*
174 isapnp_flatten(struct isapnp_attach_args
*card
)
176 struct isapnp_attach_args
*dev
, *conf
, *d
, *c
, *pa
;
178 dev
= card
->ipa_child
;
181 for (conf
= c
= NULL
, d
= dev
; d
; d
= dev
) {
182 dev
= d
->ipa_sibling
;
183 if (d
->ipa_child
== NULL
) {
185 * No subconfigurations; all configuration info
186 * is in the device node.
188 d
->ipa_sibling
= NULL
;
193 * Push down device configuration info to the
196 for (pa
= d
->ipa_child
; pa
; pa
= pa
->ipa_sibling
)
208 while (c
->ipa_sibling
)
215 /* isapnp_process_tag():
216 * Process a resource tag
219 isapnp_process_tag(u_char tag
, u_char len
, u_char
*buf
, struct isapnp_attach_args
**card
, struct isapnp_attach_args
**dev
, struct isapnp_attach_args
**conf
)
222 struct isapnp_region
*r
;
223 struct isapnp_pin
*p
;
224 struct isapnp_attach_args
*pa
;
226 #define COPY(a, b) strncpy((a), (b), sizeof(a)), (a)[sizeof(a) - 1] = '\0'
229 case ISAPNP_TAG_VERSION_NUM
:
230 DPRINTF(("PnP version %d.%d, Vendor version %d.%d\n",
231 buf
[0] >> 4, buf
[0] & 0xf, buf
[1] >> 4, buf
[1] & 0xf));
234 case ISAPNP_TAG_LOGICAL_DEV_ID
:
235 (void) isapnp_id_to_vendor(str
, buf
);
236 DPRINTF(("Logical device id %s\n", str
));
238 *dev
= isapnp_newdev(*card
);
239 COPY((*dev
)->ipa_devlogic
, str
);
242 case ISAPNP_TAG_COMPAT_DEV_ID
:
243 (void) isapnp_id_to_vendor(str
, buf
);
244 DPRINTF(("Compatible device id %s\n", str
));
249 if (*(*dev
)->ipa_devcompat
== '\0')
250 COPY((*dev
)->ipa_devcompat
, str
);
253 case ISAPNP_TAG_DEP_START
:
255 buf
[0] = ISAPNP_DEP_ACCEPTABLE
;
260 *conf
= isapnp_newconf(*dev
);
261 (*conf
)->ipa_pref
= buf
[0];
263 isapnp_print_dep_start(">>> Start dependent function ",
268 case ISAPNP_TAG_DEP_END
:
269 DPRINTF(("<<<End dependent functions\n"));
273 case ISAPNP_TAG_ANSI_IDENT_STRING
:
275 DPRINTF(("ANSI Ident: %s\n", buf
));
277 COPY((*card
)->ipa_devident
, buf
);
279 COPY((*dev
)->ipa_devclass
, buf
);
293 * Decide which configuration we add the tag to
304 case ISAPNP_TAG_IRQ_FORMAT
:
309 buf
[2] = ISAPNP_IRQTYPE_EDGE_PLUS
;
311 p
= &pa
->ipa_irq
[pa
->ipa_nirq
++];
312 p
->bits
= buf
[0] | (buf
[1] << 8);
315 isapnp_print_irq("", p
);
319 case ISAPNP_TAG_DMA_FORMAT
:
323 p
= &pa
->ipa_drq
[pa
->ipa_ndrq
++];
327 isapnp_print_drq("", p
);
332 case ISAPNP_TAG_IO_PORT_DESC
:
333 r
= &pa
->ipa_io
[pa
->ipa_nio
++];
335 r
->minbase
= (buf
[2] << 8) | buf
[1];
336 r
->maxbase
= (buf
[4] << 8) | buf
[3];
342 isapnp_print_io("", r
);
346 case ISAPNP_TAG_FIXED_IO_PORT_DESC
:
347 r
= &pa
->ipa_io
[pa
->ipa_nio
++];
349 r
->minbase
= (buf
[1] << 8) | buf
[0];
350 r
->maxbase
= r
->minbase
;
356 isapnp_print_io("FIXED ", r
);
360 case ISAPNP_TAG_VENDOR_DEF
:
361 DPRINTF(("Vendor defined (short)\n"));
364 case ISAPNP_TAG_MEM_RANGE_DESC
:
365 r
= &pa
->ipa_mem
[pa
->ipa_nmem
++];
367 r
->minbase
= (buf
[2] << 16) | (buf
[1] << 8);
368 r
->maxbase
= (buf
[4] << 16) | (buf
[3] << 8);
369 r
->align
= (buf
[6] << 8) | buf
[5];
370 r
->length
= (buf
[8] << 16) | (buf
[7] << 8);
374 isapnp_print_mem("", r
);
379 case ISAPNP_TAG_UNICODE_IDENT_STRING
:
380 DPRINTF(("Unicode Ident\n"));
383 case ISAPNP_TAG_VENDOR_DEFINED
:
384 DPRINTF(("Vendor defined (long)\n"));
387 case ISAPNP_TAG_MEM32_RANGE_DESC
:
388 r
= &pa
->ipa_mem32
[pa
->ipa_nmem32
++];
390 r
->minbase
= (buf
[4] << 24) | (buf
[3] << 16) |
391 (buf
[2] << 8) | buf
[1];
392 r
->maxbase
= (buf
[8] << 24) | (buf
[7] << 16) |
393 (buf
[6] << 8) | buf
[5];
394 r
->align
= (buf
[12] << 24) | (buf
[11] << 16) |
395 (buf
[10] << 8) | buf
[9];
396 r
->length
= (buf
[16] << 24) | (buf
[15] << 16) |
397 (buf
[14] << 8) | buf
[13];
401 isapnp_print_mem("32-bit ", r
);
405 case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC
:
406 r
= &pa
->ipa_mem32
[pa
->ipa_nmem32
++];
408 r
->minbase
= (buf
[4] << 24) | (buf
[3] << 16) |
409 (buf
[2] << 8) | buf
[1];
410 r
->maxbase
= r
->minbase
;
412 r
->length
= (buf
[8] << 24) | (buf
[7] << 16) |
413 (buf
[6] << 8) | buf
[5];
417 isapnp_print_mem("FIXED 32-bit ", r
);
425 printf("tag %.2x, len %d: ", tag
, len
);
426 for (i
= 0; i
< len
; i
++)
427 printf("%.2x ", buf
[i
]);
437 /* isapnp_get_resource():
438 * Read the resources for card c
440 struct isapnp_attach_args
*
441 isapnp_get_resource(struct isapnp_softc
*sc
, int c
)
447 struct isapnp_attach_args
*card
, *dev
= NULL
, *conf
= NULL
;
448 u_char buf
[ISAPNP_MAX_TAGSIZE
], *p
;
450 memset(buf
, 0, sizeof(buf
));
452 card
= ISAPNP_MALLOC(sizeof(*card
));
453 memset(card
, 0, sizeof(*card
));
456 if (isapnp_wait_status(sc)) \
458 d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA)
460 for (i
= 0; i
< ISAPNP_SERIAL_SIZE
; i
++) {
463 if (d
!= sc
->sc_id
[c
][i
] && i
!= ISAPNP_SERIAL_SIZE
- 1) {
465 aprint_error_dev(sc
->sc_dev
,
466 "card %d violates PnP spec; byte %d\n",
472 * Magic! If this is the first byte, we
473 * assume that the tag data begins here.
484 if (d
& ISAPNP_LARGE_TAG
) {
490 len
= (buf
[1] << 8) | buf
[0];
493 tag
= (d
>> 3) & 0xf;
497 for (p
= buf
, i
= 0; i
< len
; i
++) {
499 if (i
< ISAPNP_MAX_TAGSIZE
)
503 if (len
>= ISAPNP_MAX_TAGSIZE
) {
504 aprint_error_dev(sc
->sc_dev
,
505 "Maximum tag size exceeded, card %d\n",
507 len
= ISAPNP_MAX_TAGSIZE
- 1;
512 if (isapnp_process_tag(tag
, len
, buf
, &card
, &dev
,
514 aprint_error_dev(sc
->sc_dev
,
515 "No current device for tag, card %d\n",
521 while (tag
!= ISAPNP_TAG_END
);
522 return isapnp_flatten(card
);
525 for (card
= isapnp_flatten(card
); card
; ) {
526 dev
= card
->ipa_sibling
;
530 aprint_normal_dev(sc
->sc_dev
, "%s, card %d\n",
531 warned
>= 10 ? "Too many tag errors" : "Resource timeout", c
+ 1);