FreeBSD/Linux Kernel Cross Reference
sys/isa/pnpparse.c
1 /*-
2 * Copyright (c) 1999 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
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>
34 #include <sys/bus.h>
35 #include <isa/isavar.h>
36 #include <isa/pnpreg.h>
37 #include <isa/pnpvar.h>
38
39 #define MAXDEP 8
40
41 #define I16(p) ((p)[0] + ((p)[1] << 8))
42 #define I32(p) (I16(p) + (I16(p+2) << 16))
43
44 /*
45 * Parse resource data for Logical Devices.
46 *
47 * This function exits as soon as it gets an error reading *ANY*
48 * Resource Data or it reaches the end of Resource Data.
49 */
50 void
51 pnp_parse_resources(device_t dev, u_char *resources, int len)
52 {
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;
58 int ncfgs = 1;
59 int priorities[1 + MAXDEP];
60 struct isa_config *configs;
61 char buf[100];
62 int i;
63
64 id = isa_get_logicalid(dev);
65 configs = (struct isa_config *)malloc(sizeof(*configs) * (1 + MAXDEP),
66 M_DEVBUF, M_NOWAIT);
67 if (configs == NULL) {
68 device_printf(dev, "No memory to parse PNP data\n");
69 return;
70 }
71 bzero(configs, sizeof(*configs) * (1 + MAXDEP));
72 config = &configs[0];
73 priorities[0] = 0;
74 resp = resources;
75 while (scanning > 0) {
76 tag = *resp++;
77 scanning--;
78 if (PNP_RES_TYPE(tag) == 0) {
79 /* Small resource */
80 if (scanning < PNP_SRES_LEN(tag)) {
81 scanning = 0;
82 continue;
83 }
84 resinfo = resp;
85 resp += PNP_SRES_LEN(tag);
86 scanning -= PNP_SRES_LEN(tag);;
87
88 switch (PNP_SRES_NUM(tag)) {
89 case PNP_TAG_COMPAT_DEVICE:
90 /*
91 * Got a compatible device id
92 * resource. Should keep a list of
93 * compat ids in the device.
94 */
95 bcopy(resinfo, &compat_id, 4);
96 isa_set_compatid(dev, compat_id);
97 break;
98
99 case PNP_TAG_IRQ_FORMAT:
100 if (bootverbose) {
101 printf("%s: adding irq mask %#04x\n",
102 pnp_eisaformat(id),
103 I16(resinfo));
104 }
105 if (config->ic_nirq == ISA_NIRQ) {
106 device_printf(parent, "too many irqs\n");
107 scanning = 0;
108 break;
109 }
110 config->ic_irqmask[config->ic_nirq] =
111 I16(resinfo);
112 config->ic_nirq++;
113 break;
114
115 case PNP_TAG_DMA_FORMAT:
116 if (bootverbose) {
117 printf("%s: adding dma mask %#02x\n",
118 pnp_eisaformat(id),
119 resinfo[0]);
120 }
121 if (config->ic_ndrq == ISA_NDRQ) {
122 device_printf(parent, "too many drqs\n");
123 scanning = 0;
124 break;
125 }
126 config->ic_drqmask[config->ic_ndrq] =
127 resinfo[0];
128 config->ic_ndrq++;
129 break;
130
131 case PNP_TAG_START_DEPENDANT:
132 if (bootverbose) {
133 printf("%s: start dependant\n",
134 pnp_eisaformat(id));
135 }
136 if (ncfgs > MAXDEP) {
137 device_printf(parent, "too many dependant configs (%d)\n", MAXDEP);
138 scanning = 0;
139 break;
140 }
141 config = &configs[ncfgs];
142 /*
143 * If the priority is not specified,
144 * then use the default of
145 * 'acceptable'
146 */
147 if (PNP_SRES_LEN(tag) > 0)
148 priorities[ncfgs] = resinfo[0];
149 else
150 priorities[ncfgs] = 1;
151 ncfgs++;
152 break;
153
154 case PNP_TAG_END_DEPENDANT:
155 if (bootverbose) {
156 printf("%s: end dependant\n",
157 pnp_eisaformat(id));
158 }
159 config = &configs[0]; /* back to main config */
160 break;
161
162 case PNP_TAG_IO_RANGE:
163 if (bootverbose) {
164 printf("%s: adding io range "
165 "%#x-%#x, size=%#x, "
166 "align=%#x\n",
167 pnp_eisaformat(id),
168 I16(resinfo + 1),
169 I16(resinfo + 3) + resinfo[6]-1,
170 resinfo[6],
171 resinfo[5]);
172 }
173 if (config->ic_nport == ISA_NPORT) {
174 device_printf(parent, "too many ports\n");
175 scanning = 0;
176 break;
177 }
178 config->ic_port[config->ic_nport].ir_start =
179 I16(resinfo + 1);
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 =
183 resinfo[6];
184 if (resinfo[5] == 0) {
185 /* Make sure align is at least one */
186 resinfo[5] = 1;
187 }
188 config->ic_port[config->ic_nport].ir_align =
189 resinfo[5];
190 config->ic_nport++;
191 break;
192
193 case PNP_TAG_IO_FIXED:
194 if (bootverbose) {
195 printf("%s: adding fixed io range "
196 "%#x-%#x, size=%#x, "
197 "align=%#x\n",
198 pnp_eisaformat(id),
199 I16(resinfo),
200 I16(resinfo) + resinfo[2] - 1,
201 resinfo[2],
202 1);
203 }
204 if (config->ic_nport == ISA_NPORT) {
205 device_printf(parent, "too many ports\n");
206 scanning = 0;
207 break;
208 }
209 config->ic_port[config->ic_nport].ir_start =
210 I16(resinfo);
211 config->ic_port[config->ic_nport].ir_end =
212 I16(resinfo) + resinfo[2] - 1;
213 config->ic_port[config->ic_nport].ir_size
214 = resinfo[2];
215 config->ic_port[config->ic_nport].ir_align = 1;
216 config->ic_nport++;
217 break;
218
219 case PNP_TAG_END:
220 if (bootverbose) {
221 printf("%s: end config\n",
222 pnp_eisaformat(id));
223 }
224 scanning = 0;
225 break;
226
227 default:
228 /* Skip this resource */
229 device_printf(parent, "unexpected small tag %d\n",
230 PNP_SRES_NUM(tag));
231 break;
232 }
233 } else {
234 /* Large resource */
235 if (scanning < 2) {
236 scanning = 0;
237 continue;
238 }
239 large_len = I16(resp);
240 resp += 2;
241 scanning -= 2;
242
243 if (scanning < large_len) {
244 scanning = 0;
245 continue;
246 }
247 resinfo = resp;
248 resp += large_len;
249 scanning -= large_len;
250
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);
256
257 /*
258 * Trim trailing spaces and garbage.
259 */
260 while (large_len > 0 && buf[large_len - 1] <= ' ')
261 large_len--;
262 buf[large_len] = '\0';
263 device_set_desc_copy(dev, buf);
264 break;
265
266 case PNP_TAG_MEMORY_RANGE:
267 if (bootverbose) {
268 int temp = I16(resinfo + 7) << 8;
269
270 printf("%s: adding memory range "
271 "%#x-%#x, size=%#x, "
272 "align=%#x\n",
273 pnp_eisaformat(id),
274 I16(resinfo + 1)<<8,
275 (I16(resinfo + 3)<<8) + temp - 1,
276 temp,
277 I16(resinfo + 5));
278 }
279
280 if (config->ic_nmem == ISA_NMEM) {
281 device_printf(parent, "too many memory ranges\n");
282 scanning = 0;
283 break;
284 }
285
286 config->ic_mem[config->ic_nmem].ir_start =
287 I16(resinfo + 1)<<8;
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 =
294 I16(resinfo + 5);
295 if (!config->ic_mem[config->ic_nmem].ir_align)
296 config->ic_mem[config->ic_nmem]
297 .ir_align = 0x10000;
298 config->ic_nmem++;
299 break;
300
301 case PNP_TAG_MEMORY32_RANGE:
302 if (I32(resinfo + 13) == 0) {
303 if (bootverbose) {
304 printf("%s: skipping empty range\n",
305 pnp_eisaformat(id));
306 }
307 continue;
308 }
309 if (bootverbose) {
310 printf("%s: adding memory32 range "
311 "%#x-%#x, size=%#x, "
312 "align=%#x\n",
313 pnp_eisaformat(id),
314 I32(resinfo + 1),
315 I32(resinfo + 5)
316 + I32(resinfo + 13) - 1,
317 I32(resinfo + 13),
318 I32(resinfo + 9));
319 }
320
321 if (config->ic_nmem == ISA_NMEM) {
322 device_printf(parent, "too many memory ranges\n");
323 scanning = 0;
324 break;
325 }
326
327 config->ic_mem[config->ic_nmem].ir_start =
328 I32(resinfo + 1);
329 config->ic_mem[config->ic_nmem].ir_end =
330 I32(resinfo + 5)
331 + I32(resinfo + 13) - 1;
332 config->ic_mem[config->ic_nmem].ir_size =
333 I32(resinfo + 13);
334 config->ic_mem[config->ic_nmem].ir_align =
335 I32(resinfo + 9);
336 config->ic_nmem++;
337 break;
338
339 case PNP_TAG_MEMORY32_FIXED:
340 if (I32(resinfo + 5) == 0) {
341 if (bootverbose) {
342 printf("%s: skipping empty range\n",
343 pnp_eisaformat(id));
344 }
345 continue;
346 }
347 if (bootverbose) {
348 printf("%s: adding fixed memory32 range "
349 "%#x-%#x, size=%#x\n",
350 pnp_eisaformat(id),
351 I32(resinfo + 1),
352 I32(resinfo + 1)
353 + I32(resinfo + 5) - 1,
354 I32(resinfo + 5));
355 }
356
357 if (config->ic_nmem == ISA_NMEM) {
358 device_printf(parent, "too many memory ranges\n");
359 scanning = 0;
360 break;
361 }
362
363 config->ic_mem[config->ic_nmem].ir_start =
364 I32(resinfo + 1);
365 config->ic_mem[config->ic_nmem].ir_end =
366 I32(resinfo + 1)
367 + I32(resinfo + 5) - 1;
368 config->ic_mem[config->ic_nmem].ir_size =
369 I32(resinfo + 5);
370 config->ic_mem[config->ic_nmem].ir_align = 1;
371 config->ic_nmem++;
372 break;
373
374 default:
375 /* Skip this resource */
376 device_printf(parent, "unexpected large tag %d\n",
377 PNP_SRES_NUM(tag));
378 }
379 }
380 }
381 if(ncfgs == 1) {
382 /* Single config without dependants */
383 (void)ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]);
384 free(configs, M_DEVBUF);
385 return;
386 }
387 /* Cycle through dependant configs merging primary details */
388 for(i = 1; i < ncfgs; i++) {
389 int j;
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);
395 return;
396 }
397 config->ic_mem[config->ic_nmem] = configs[0].ic_mem[j];
398 config->ic_nmem++;
399 }
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);
404 return;
405 }
406 config->ic_port[config->ic_nport] = configs[0].ic_port[j];
407 config->ic_nport++;
408 }
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);
413 return;
414 }
415 config->ic_irqmask[config->ic_nirq] = configs[0].ic_irqmask[j];
416 config->ic_nirq++;
417 }
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);
422 return;
423 }
424 config->ic_drqmask[config->ic_ndrq] = configs[0].ic_drqmask[j];
425 config->ic_ndrq++;
426 }
427 (void)ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]);
428 }
429 free(configs, M_DEVBUF);
430 }
Cache object: 74966080b978495044cc2eff411b982f
|