2 * Copyright (c) 1999 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sys/isa/pnpparse.c,v 1.2.2.3 2000/11/07 05:53:55 msmith Exp $
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/module.h>
35 #include <isa/isavar.h>
36 #include <isa/pnpreg.h>
37 #include <isa/pnpvar.h>
41 #define I16(p) ((p)[0] + ((p)[1] << 8))
42 #define I32(p) (I16(p) + (I16(p+2) << 16))
45 * Parse resource data for Logical Devices.
47 * This function exits as soon as it gets an error reading *ANY*
48 * Resource Data or it reaches the end of Resource Data.
51 pnp_parse_resources(device_t dev, u_char *resources, int len)
53 device_t parent = device_get_parent(dev);
54 u_char tag, *resp, *resinfo;
55 int large_len, scanning = len;
56 u_int32_t id, compat_id;
57 struct isa_config *config;
59 int priorities[1 + MAXDEP];
60 struct isa_config *configs;
64 id = isa_get_logicalid(dev);
65 configs = (struct isa_config *)malloc(sizeof(*configs) * (1 + MAXDEP),
67 if (configs == NULL) {
68 device_printf(dev, "No memory to parse PNP data\n");
71 bzero(configs, sizeof(*configs) * (1 + MAXDEP));
75 while (scanning > 0) {
78 if (PNP_RES_TYPE(tag) == 0) {
80 if (scanning < PNP_SRES_LEN(tag)) {
85 resp += PNP_SRES_LEN(tag);
86 scanning -= PNP_SRES_LEN(tag);;
88 switch (PNP_SRES_NUM(tag)) {
89 case PNP_TAG_COMPAT_DEVICE:
91 * Got a compatible device id
92 * resource. Should keep a list of
93 * compat ids in the device.
95 bcopy(resinfo, &compat_id, 4);
96 isa_set_compatid(dev, compat_id);
99 case PNP_TAG_IRQ_FORMAT:
101 printf("%s: adding irq mask %#04x\n",
105 if (config->ic_nirq == ISA_NIRQ) {
106 device_printf(parent, "too many irqs\n");
110 config->ic_irqmask[config->ic_nirq] =
115 case PNP_TAG_DMA_FORMAT:
117 printf("%s: adding dma mask %#02x\n",
121 if (config->ic_ndrq == ISA_NDRQ) {
122 device_printf(parent, "too many drqs\n");
126 config->ic_drqmask[config->ic_ndrq] =
131 case PNP_TAG_START_DEPENDANT:
133 printf("%s: start dependant\n",
136 if (ncfgs >= MAXDEP) {
137 device_printf(parent, "too many dependant configs (%d)\n", MAXDEP);
141 config = &configs[ncfgs];
143 * If the priority is not specified,
144 * then use the default of
147 if (PNP_SRES_LEN(tag) > 0)
148 priorities[ncfgs] = resinfo[0];
150 priorities[ncfgs] = 1;
154 case PNP_TAG_END_DEPENDANT:
156 printf("%s: end dependant\n",
159 config = &configs[0]; /* back to main config */
162 case PNP_TAG_IO_RANGE:
164 printf("%s: adding io range "
165 "%#x-%#x, size=%#x, "
169 I16(resinfo + 3) + resinfo[6]-1,
173 if (config->ic_nport == ISA_NPORT) {
174 device_printf(parent, "too many ports\n");
178 config->ic_port[config->ic_nport].ir_start =
180 config->ic_port[config->ic_nport].ir_end =
181 I16(resinfo + 3) + resinfo[6] - 1;
182 config->ic_port[config->ic_nport].ir_size =
184 if (resinfo[5] == 0) {
185 /* Make sure align is at least one */
188 config->ic_port[config->ic_nport].ir_align =
193 case PNP_TAG_IO_FIXED:
195 printf("%s: adding fixed io range "
196 "%#x-%#x, size=%#x, "
200 I16(resinfo) + resinfo[2] - 1,
204 if (config->ic_nport == ISA_NPORT) {
205 device_printf(parent, "too many ports\n");
209 config->ic_port[config->ic_nport].ir_start =
211 config->ic_port[config->ic_nport].ir_end =
212 I16(resinfo) + resinfo[2] - 1;
213 config->ic_port[config->ic_nport].ir_size
215 config->ic_port[config->ic_nport].ir_align = 1;
221 printf("%s: end config\n",
228 /* Skip this resource */
229 device_printf(parent, "unexpected small tag %d\n",
239 large_len = I16(resp);
243 if (scanning < large_len) {
249 scanning -= large_len;
251 switch (PNP_LRES_NUM(tag)) {
252 case PNP_TAG_ID_ANSI:
253 if (large_len > sizeof(buf) - 1)
254 large_len = sizeof(buf) - 1;
255 bcopy(resinfo, buf, large_len);
258 * Trim trailing spaces and garbage.
260 while (large_len > 0 && buf[large_len - 1] <= ' ')
262 buf[large_len] = '\0';
263 device_set_desc_copy(dev, buf);
266 case PNP_TAG_MEMORY_RANGE:
268 int temp = I16(resinfo + 7) << 8;
270 printf("%s: adding memory range "
271 "%#x-%#x, size=%#x, "
275 (I16(resinfo + 3)<<8) + temp - 1,
280 if (config->ic_nmem == ISA_NMEM) {
281 device_printf(parent, "too many memory ranges\n");
286 config->ic_mem[config->ic_nmem].ir_start =
288 config->ic_mem[config->ic_nmem].ir_end =
289 (I16(resinfo + 3)<<8)
290 + (I16(resinfo + 7) << 8) - 1;
291 config->ic_mem[config->ic_nmem].ir_size =
292 I16(resinfo + 7) << 8;
293 config->ic_mem[config->ic_nmem].ir_align =
295 if (!config->ic_mem[config->ic_nmem].ir_align)
296 config->ic_mem[config->ic_nmem]
301 case PNP_TAG_MEMORY32_RANGE:
302 if (I32(resinfo + 13) == 0) {
304 printf("%s: skipping empty range\n",
310 printf("%s: adding memory32 range "
311 "%#x-%#x, size=%#x, "
316 + I32(resinfo + 13) - 1,
321 if (config->ic_nmem == ISA_NMEM) {
322 device_printf(parent, "too many memory ranges\n");
327 config->ic_mem[config->ic_nmem].ir_start =
329 config->ic_mem[config->ic_nmem].ir_end =
331 + I32(resinfo + 13) - 1;
332 config->ic_mem[config->ic_nmem].ir_size =
334 config->ic_mem[config->ic_nmem].ir_align =
339 case PNP_TAG_MEMORY32_FIXED:
340 if (I32(resinfo + 5) == 0) {
342 printf("%s: skipping empty range\n",
348 printf("%s: adding fixed memory32 range "
349 "%#x-%#x, size=%#x\n",
353 + I32(resinfo + 5) - 1,
357 if (config->ic_nmem == ISA_NMEM) {
358 device_printf(parent, "too many memory ranges\n");
363 config->ic_mem[config->ic_nmem].ir_start =
365 config->ic_mem[config->ic_nmem].ir_end =
367 + I32(resinfo + 5) - 1;
368 config->ic_mem[config->ic_nmem].ir_size =
370 config->ic_mem[config->ic_nmem].ir_align = 1;
375 /* Skip this resource */
376 device_printf(parent, "unexpected large tag %d\n",
382 /* Single config without dependants */
383 (void)ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]);
384 free(configs, M_DEVBUF);
387 /* Cycle through dependant configs merging primary details */
388 for(i = 1; i < ncfgs; i++) {
390 config = &configs[i];
391 for(j = 0; j < configs[0].ic_nmem; j++) {
392 if (config->ic_nmem == ISA_NMEM) {
393 device_printf(parent, "too many memory ranges\n");
394 free(configs, M_DEVBUF);
397 config->ic_mem[config->ic_nmem] = configs[0].ic_mem[j];
400 for(j = 0; j < configs[0].ic_nport; j++) {
401 if (config->ic_nport == ISA_NPORT) {
402 device_printf(parent, "too many port ranges\n");
403 free(configs, M_DEVBUF);
406 config->ic_port[config->ic_nport] = configs[0].ic_port[j];
409 for(j = 0; j < configs[0].ic_nirq; j++) {
410 if (config->ic_nirq == ISA_NIRQ) {
411 device_printf(parent, "too many irq ranges\n");
412 free(configs, M_DEVBUF);
415 config->ic_irqmask[config->ic_nirq] = configs[0].ic_irqmask[j];
418 for(j = 0; j < configs[0].ic_ndrq; j++) {
419 if (config->ic_ndrq == ISA_NDRQ) {
420 device_printf(parent, "too many drq ranges\n");
421 free(configs, M_DEVBUF);
424 config->ic_drqmask[config->ic_ndrq] = configs[0].ic_drqmask[j];
427 (void)ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]);
429 free(configs, M_DEVBUF);