xref: /openbmc/linux/drivers/pnp/pnpbios/rsparser.c (revision 87c2ce3b)
1 /*
2  * rsparser.c - parses and encodes pnpbios resource data streams
3  *
4  */
5 
6 #include <linux/config.h>
7 #include <linux/ctype.h>
8 #include <linux/pnp.h>
9 #include <linux/pnpbios.h>
10 #include <linux/string.h>
11 #include <linux/slab.h>
12 
13 #ifdef CONFIG_PCI
14 #include <linux/pci.h>
15 #else
16 inline void pcibios_penalize_isa_irq(int irq, int active) {}
17 #endif /* CONFIG_PCI */
18 
19 #include "pnpbios.h"
20 
21 /* standard resource tags */
22 #define SMALL_TAG_PNPVERNO		0x01
23 #define SMALL_TAG_LOGDEVID		0x02
24 #define SMALL_TAG_COMPATDEVID		0x03
25 #define SMALL_TAG_IRQ			0x04
26 #define SMALL_TAG_DMA			0x05
27 #define SMALL_TAG_STARTDEP		0x06
28 #define SMALL_TAG_ENDDEP		0x07
29 #define SMALL_TAG_PORT			0x08
30 #define SMALL_TAG_FIXEDPORT		0x09
31 #define SMALL_TAG_VENDOR		0x0e
32 #define SMALL_TAG_END			0x0f
33 #define LARGE_TAG			0x80
34 #define LARGE_TAG_MEM			0x81
35 #define LARGE_TAG_ANSISTR		0x82
36 #define LARGE_TAG_UNICODESTR		0x83
37 #define LARGE_TAG_VENDOR		0x84
38 #define LARGE_TAG_MEM32			0x85
39 #define LARGE_TAG_FIXEDMEM32		0x86
40 
41 /*
42  * Resource Data Stream Format:
43  *
44  * Allocated Resources (required)
45  * end tag ->
46  * Resource Configuration Options (optional)
47  * end tag ->
48  * Compitable Device IDs (optional)
49  * final end tag ->
50  */
51 
52 /*
53  * Allocated Resources
54  */
55 
56 static void
57 pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
58 {
59 	int i = 0;
60 	while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_IRQ) i++;
61 	if (i < PNP_MAX_IRQ) {
62 		res->irq_resource[i].flags = IORESOURCE_IRQ;  // Also clears _UNSET flag
63 		if (irq == -1) {
64 			res->irq_resource[i].flags |= IORESOURCE_DISABLED;
65 			return;
66 		}
67 		res->irq_resource[i].start =
68 		res->irq_resource[i].end = (unsigned long) irq;
69 		pcibios_penalize_isa_irq(irq, 1);
70 	}
71 }
72 
73 static void
74 pnpbios_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
75 {
76 	int i = 0;
77 	while (i < PNP_MAX_DMA &&
78 			!(res->dma_resource[i].flags & IORESOURCE_UNSET))
79 		i++;
80 	if (i < PNP_MAX_DMA) {
81 		res->dma_resource[i].flags = IORESOURCE_DMA;  // Also clears _UNSET flag
82 		if (dma == -1) {
83 			res->dma_resource[i].flags |= IORESOURCE_DISABLED;
84 			return;
85 		}
86 		res->dma_resource[i].start =
87 		res->dma_resource[i].end = (unsigned long) dma;
88 	}
89 }
90 
91 static void
92 pnpbios_parse_allocated_ioresource(struct pnp_resource_table * res, int io, int len)
93 {
94 	int i = 0;
95 	while (!(res->port_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_PORT) i++;
96 	if (i < PNP_MAX_PORT) {
97 		res->port_resource[i].flags = IORESOURCE_IO;  // Also clears _UNSET flag
98 		if (len <= 0 || (io + len -1) >= 0x10003) {
99 			res->port_resource[i].flags |= IORESOURCE_DISABLED;
100 			return;
101 		}
102 		res->port_resource[i].start = (unsigned long) io;
103 		res->port_resource[i].end = (unsigned long)(io + len - 1);
104 	}
105 }
106 
107 static void
108 pnpbios_parse_allocated_memresource(struct pnp_resource_table * res, int mem, int len)
109 {
110 	int i = 0;
111 	while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_MEM) i++;
112 	if (i < PNP_MAX_MEM) {
113 		res->mem_resource[i].flags = IORESOURCE_MEM;  // Also clears _UNSET flag
114 		if (len <= 0) {
115 			res->mem_resource[i].flags |= IORESOURCE_DISABLED;
116 			return;
117 		}
118 		res->mem_resource[i].start = (unsigned long) mem;
119 		res->mem_resource[i].end = (unsigned long)(mem + len - 1);
120 	}
121 }
122 
123 static unsigned char *
124 pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
125 {
126 	unsigned int len, tag;
127 	int io, size, mask, i;
128 
129 	if (!p)
130 		return NULL;
131 
132 	/* Blank the resource table values */
133 	pnp_init_resource_table(res);
134 
135 	while ((char *)p < (char *)end) {
136 
137 		/* determine the type of tag */
138 		if (p[0] & LARGE_TAG) { /* large tag */
139 			len = (p[2] << 8) | p[1];
140 			tag = p[0];
141 		} else { /* small tag */
142 			len = p[0] & 0x07;
143 			tag = ((p[0]>>3) & 0x0f);
144 		}
145 
146 		switch (tag) {
147 
148 		case LARGE_TAG_MEM:
149 			if (len != 9)
150 				goto len_err;
151 			io = *(short *) &p[4];
152 			size = *(short *) &p[10];
153 			pnpbios_parse_allocated_memresource(res, io, size);
154 			break;
155 
156 		case LARGE_TAG_ANSISTR:
157 			/* ignore this for now */
158 			break;
159 
160 		case LARGE_TAG_VENDOR:
161 			/* do nothing */
162 			break;
163 
164 		case LARGE_TAG_MEM32:
165 			if (len != 17)
166 				goto len_err;
167 			io = *(int *) &p[4];
168 			size = *(int *) &p[16];
169 			pnpbios_parse_allocated_memresource(res, io, size);
170 			break;
171 
172 		case LARGE_TAG_FIXEDMEM32:
173 			if (len != 9)
174 				goto len_err;
175 			io = *(int *) &p[4];
176 			size = *(int *) &p[8];
177 			pnpbios_parse_allocated_memresource(res, io, size);
178 			break;
179 
180 		case SMALL_TAG_IRQ:
181 			if (len < 2 || len > 3)
182 				goto len_err;
183 			io = -1;
184 			mask= p[1] + p[2]*256;
185 			for (i=0;i<16;i++, mask=mask>>1)
186 				if(mask & 0x01) io=i;
187 			pnpbios_parse_allocated_irqresource(res, io);
188 			break;
189 
190 		case SMALL_TAG_DMA:
191 			if (len != 2)
192 				goto len_err;
193 			io = -1;
194 			mask = p[1];
195 			for (i=0;i<8;i++, mask = mask>>1)
196 				if(mask & 0x01) io=i;
197 			pnpbios_parse_allocated_dmaresource(res, io);
198 			break;
199 
200 		case SMALL_TAG_PORT:
201 			if (len != 7)
202 				goto len_err;
203 			io = p[2] + p[3] *256;
204 			size = p[7];
205 			pnpbios_parse_allocated_ioresource(res, io, size);
206 			break;
207 
208 		case SMALL_TAG_VENDOR:
209 			/* do nothing */
210 			break;
211 
212 		case SMALL_TAG_FIXEDPORT:
213 			if (len != 3)
214 				goto len_err;
215 			io = p[1] + p[2] * 256;
216 			size = p[3];
217 			pnpbios_parse_allocated_ioresource(res, io, size);
218 			break;
219 
220 		case SMALL_TAG_END:
221 			p = p + 2;
222         		return (unsigned char *)p;
223 			break;
224 
225 		default: /* an unkown tag */
226 			len_err:
227 			printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
228 			break;
229 		}
230 
231 		/* continue to the next tag */
232 		if (p[0] & LARGE_TAG)
233 			p += len + 3;
234 		else
235 			p += len + 1;
236 	}
237 
238 	printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
239 
240 	return NULL;
241 }
242 
243 
244 /*
245  * Resource Configuration Options
246  */
247 
248 static void
249 pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
250 {
251 	struct pnp_mem * mem;
252 	mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
253 	if (!mem)
254 		return;
255 	mem->min = ((p[5] << 8) | p[4]) << 8;
256 	mem->max = ((p[7] << 8) | p[6]) << 8;
257 	mem->align = (p[9] << 8) | p[8];
258 	mem->size = ((p[11] << 8) | p[10]) << 8;
259 	mem->flags = p[3];
260 	pnp_register_mem_resource(option,mem);
261 	return;
262 }
263 
264 static void
265 pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
266 {
267 	struct pnp_mem * mem;
268 	mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
269 	if (!mem)
270 		return;
271 	mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
272 	mem->max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
273 	mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
274 	mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
275 	mem->flags = p[3];
276 	pnp_register_mem_resource(option,mem);
277 	return;
278 }
279 
280 static void
281 pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
282 {
283 	struct pnp_mem * mem;
284 	mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
285 	if (!mem)
286 		return;
287 	mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
288 	mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
289 	mem->align = 0;
290 	mem->flags = p[3];
291 	pnp_register_mem_resource(option,mem);
292 	return;
293 }
294 
295 static void
296 pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
297 {
298 	struct pnp_irq * irq;
299 	unsigned long bits;
300 
301 	irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
302 	if (!irq)
303 		return;
304 	bits = (p[2] << 8) | p[1];
305 	bitmap_copy(irq->map, &bits, 16);
306 	if (size > 2)
307 		irq->flags = p[3];
308 	else
309 		irq->flags = IORESOURCE_IRQ_HIGHEDGE;
310 	pnp_register_irq_resource(option,irq);
311 	return;
312 }
313 
314 static void
315 pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
316 {
317 	struct pnp_dma * dma;
318 	dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
319 	if (!dma)
320 		return;
321 	dma->map = p[1];
322 	dma->flags = p[2];
323 	pnp_register_dma_resource(option,dma);
324 	return;
325 }
326 
327 static void
328 pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
329 {
330 	struct pnp_port * port;
331 	port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
332 	if (!port)
333 		return;
334 	port->min = (p[3] << 8) | p[2];
335 	port->max = (p[5] << 8) | p[4];
336 	port->align = p[6];
337 	port->size = p[7];
338 	port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
339 	pnp_register_port_resource(option,port);
340 	return;
341 }
342 
343 static void
344 pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
345 {
346 	struct pnp_port * port;
347 	port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
348 	if (!port)
349 		return;
350 	port->min = port->max = (p[2] << 8) | p[1];
351 	port->size = p[3];
352 	port->align = 0;
353 	port->flags = PNP_PORT_FLAG_FIXED;
354 	pnp_register_port_resource(option,port);
355 	return;
356 }
357 
358 static unsigned char *
359 pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struct pnp_dev *dev)
360 {
361 	unsigned int len, tag;
362 	int priority = 0;
363 	struct pnp_option *option, *option_independent;
364 
365 	if (!p)
366 		return NULL;
367 
368 	option_independent = option = pnp_register_independent_option(dev);
369 	if (!option)
370 		return NULL;
371 
372 	while ((char *)p < (char *)end) {
373 
374 		/* determine the type of tag */
375 		if (p[0] & LARGE_TAG) { /* large tag */
376 			len = (p[2] << 8) | p[1];
377 			tag = p[0];
378 		} else { /* small tag */
379 			len = p[0] & 0x07;
380 			tag = ((p[0]>>3) & 0x0f);
381 		}
382 
383 		switch (tag) {
384 
385 		case LARGE_TAG_MEM:
386 			if (len != 9)
387 				goto len_err;
388 			pnpbios_parse_mem_option(p, len, option);
389 			break;
390 
391 		case LARGE_TAG_MEM32:
392 			if (len != 17)
393 				goto len_err;
394 			pnpbios_parse_mem32_option(p, len, option);
395 			break;
396 
397 		case LARGE_TAG_FIXEDMEM32:
398 			if (len != 9)
399 				goto len_err;
400 			pnpbios_parse_fixed_mem32_option(p, len, option);
401 			break;
402 
403 		case SMALL_TAG_IRQ:
404 			if (len < 2 || len > 3)
405 				goto len_err;
406 			pnpbios_parse_irq_option(p, len, option);
407 			break;
408 
409 		case SMALL_TAG_DMA:
410 			if (len != 2)
411 				goto len_err;
412 			pnpbios_parse_dma_option(p, len, option);
413 			break;
414 
415 		case SMALL_TAG_PORT:
416 			if (len != 7)
417 				goto len_err;
418 			pnpbios_parse_port_option(p, len, option);
419 			break;
420 
421 		case SMALL_TAG_VENDOR:
422 			/* do nothing */
423 			break;
424 
425 		case SMALL_TAG_FIXEDPORT:
426 			if (len != 3)
427 				goto len_err;
428 			pnpbios_parse_fixed_port_option(p, len, option);
429 			break;
430 
431 		case SMALL_TAG_STARTDEP:
432 			if (len > 1)
433 				goto len_err;
434 			priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
435 			if (len > 0)
436 				priority = 0x100 | p[1];
437 			option = pnp_register_dependent_option(dev, priority);
438 			if (!option)
439 				return NULL;
440 			break;
441 
442 		case SMALL_TAG_ENDDEP:
443 			if (len != 0)
444 				goto len_err;
445 			if (option_independent == option)
446 				printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
447 			option = option_independent;
448 			break;
449 
450 		case SMALL_TAG_END:
451 			if (option_independent != option)
452 				printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_ENDDEP tag\n");
453 			p = p + 2;
454         		return (unsigned char *)p;
455 			break;
456 
457 		default: /* an unkown tag */
458 			len_err:
459 			printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
460 			break;
461 		}
462 
463 		/* continue to the next tag */
464 		if (p[0] & LARGE_TAG)
465 			p += len + 3;
466 		else
467 			p += len + 1;
468 	}
469 
470 	printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
471 
472 	return NULL;
473 }
474 
475 
476 /*
477  * Compatible Device IDs
478  */
479 
480 #define HEX(id,a) hex[((id)>>a) & 15]
481 #define CHAR(id,a) (0x40 + (((id)>>a) & 31))
482 //
483 
484 void pnpid32_to_pnpid(u32 id, char *str)
485 {
486 	const char *hex = "0123456789abcdef";
487 
488 	id = be32_to_cpu(id);
489 	str[0] = CHAR(id, 26);
490 	str[1] = CHAR(id, 21);
491 	str[2] = CHAR(id,16);
492 	str[3] = HEX(id, 12);
493 	str[4] = HEX(id, 8);
494 	str[5] = HEX(id, 4);
495 	str[6] = HEX(id, 0);
496 	str[7] = '\0';
497 
498 	return;
499 }
500 //
501 #undef CHAR
502 #undef HEX
503 
504 static unsigned char *
505 pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_dev *dev)
506 {
507 	int len, tag;
508 	char id[8];
509 	struct pnp_id *dev_id;
510 
511 	if (!p)
512 		return NULL;
513 
514 	while ((char *)p < (char *)end) {
515 
516 		/* determine the type of tag */
517 		if (p[0] & LARGE_TAG) { /* large tag */
518 			len = (p[2] << 8) | p[1];
519 			tag = p[0];
520 		} else { /* small tag */
521 			len = p[0] & 0x07;
522 			tag = ((p[0]>>3) & 0x0f);
523 		}
524 
525 		switch (tag) {
526 
527 		case LARGE_TAG_ANSISTR:
528 			strncpy(dev->name, p + 3, len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
529 			dev->name[len >= PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
530 			break;
531 
532 		case SMALL_TAG_COMPATDEVID: /* compatible ID */
533 			if (len != 4)
534 				goto len_err;
535 			dev_id =  kcalloc(1, sizeof (struct pnp_id), GFP_KERNEL);
536 			if (!dev_id)
537 				return NULL;
538 			memset(dev_id, 0, sizeof(struct pnp_id));
539 			pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,id);
540 			memcpy(&dev_id->id, id, 7);
541 			pnp_add_id(dev_id, dev);
542 			break;
543 
544 		case SMALL_TAG_END:
545 			p = p + 2;
546         		return (unsigned char *)p;
547 			break;
548 
549 		default: /* an unkown tag */
550 			len_err:
551 			printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
552 			break;
553 		}
554 
555 		/* continue to the next tag */
556 		if (p[0] & LARGE_TAG)
557 			p += len + 3;
558 		else
559 			p += len + 1;
560 	}
561 
562 	printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
563 
564 	return NULL;
565 }
566 
567 
568 /*
569  * Allocated Resource Encoding
570  */
571 
572 static void pnpbios_encode_mem(unsigned char *p, struct resource * res)
573 {
574 	unsigned long base = res->start;
575 	unsigned long len = res->end - res->start + 1;
576 	p[4] = (base >> 8) & 0xff;
577 	p[5] = ((base >> 8) >> 8) & 0xff;
578 	p[6] = (base >> 8) & 0xff;
579 	p[7] = ((base >> 8) >> 8) & 0xff;
580 	p[10] = (len >> 8) & 0xff;
581 	p[11] = ((len >> 8) >> 8) & 0xff;
582 	return;
583 }
584 
585 static void pnpbios_encode_mem32(unsigned char *p, struct resource * res)
586 {
587 	unsigned long base = res->start;
588 	unsigned long len = res->end - res->start + 1;
589 	p[4] = base & 0xff;
590 	p[5] = (base >> 8) & 0xff;
591 	p[6] = (base >> 16) & 0xff;
592 	p[7] = (base >> 24) & 0xff;
593 	p[8] = base & 0xff;
594 	p[9] = (base >> 8) & 0xff;
595 	p[10] = (base >> 16) & 0xff;
596 	p[11] = (base >> 24) & 0xff;
597 	p[16] = len & 0xff;
598 	p[17] = (len >> 8) & 0xff;
599 	p[18] = (len >> 16) & 0xff;
600 	p[19] = (len >> 24) & 0xff;
601 	return;
602 }
603 
604 static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource * res)
605 {	unsigned long base = res->start;
606 	unsigned long len = res->end - res->start + 1;
607 	p[4] = base & 0xff;
608 	p[5] = (base >> 8) & 0xff;
609 	p[6] = (base >> 16) & 0xff;
610 	p[7] = (base >> 24) & 0xff;
611 	p[8] = len & 0xff;
612 	p[9] = (len >> 8) & 0xff;
613 	p[10] = (len >> 16) & 0xff;
614 	p[11] = (len >> 24) & 0xff;
615 	return;
616 }
617 
618 static void pnpbios_encode_irq(unsigned char *p, struct resource * res)
619 {
620 	unsigned long map = 0;
621 	map = 1 << res->start;
622 	p[1] = map & 0xff;
623 	p[2] = (map >> 8) & 0xff;
624 	return;
625 }
626 
627 static void pnpbios_encode_dma(unsigned char *p, struct resource * res)
628 {
629 	unsigned long map = 0;
630 	map = 1 << res->start;
631 	p[1] = map & 0xff;
632 	return;
633 }
634 
635 static void pnpbios_encode_port(unsigned char *p, struct resource * res)
636 {
637 	unsigned long base = res->start;
638 	unsigned long len = res->end - res->start + 1;
639 	p[2] = base & 0xff;
640 	p[3] = (base >> 8) & 0xff;
641 	p[4] = base & 0xff;
642 	p[5] = (base >> 8) & 0xff;
643 	p[7] = len & 0xff;
644 	return;
645 }
646 
647 static void pnpbios_encode_fixed_port(unsigned char *p, struct resource * res)
648 {
649 	unsigned long base = res->start;
650 	unsigned long len = res->end - res->start + 1;
651 	p[1] = base & 0xff;
652 	p[2] = (base >> 8) & 0xff;
653 	p[3] = len & 0xff;
654 	return;
655 }
656 
657 static unsigned char *
658 pnpbios_encode_allocated_resource_data(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
659 {
660 	unsigned int len, tag;
661 	int port = 0, irq = 0, dma = 0, mem = 0;
662 
663 	if (!p)
664 		return NULL;
665 
666 	while ((char *)p < (char *)end) {
667 
668 		/* determine the type of tag */
669 		if (p[0] & LARGE_TAG) { /* large tag */
670 			len = (p[2] << 8) | p[1];
671 			tag = p[0];
672 		} else { /* small tag */
673 			len = p[0] & 0x07;
674 			tag = ((p[0]>>3) & 0x0f);
675 		}
676 
677 		switch (tag) {
678 
679 		case LARGE_TAG_MEM:
680 			if (len != 9)
681 				goto len_err;
682 			pnpbios_encode_mem(p, &res->mem_resource[mem]);
683 			mem++;
684 			break;
685 
686 		case LARGE_TAG_MEM32:
687 			if (len != 17)
688 				goto len_err;
689 			pnpbios_encode_mem32(p, &res->mem_resource[mem]);
690 			mem++;
691 			break;
692 
693 		case LARGE_TAG_FIXEDMEM32:
694 			if (len != 9)
695 				goto len_err;
696 			pnpbios_encode_fixed_mem32(p, &res->mem_resource[mem]);
697 			mem++;
698 			break;
699 
700 		case SMALL_TAG_IRQ:
701 			if (len < 2 || len > 3)
702 				goto len_err;
703 			pnpbios_encode_irq(p, &res->irq_resource[irq]);
704 			irq++;
705 			break;
706 
707 		case SMALL_TAG_DMA:
708 			if (len != 2)
709 				goto len_err;
710 			pnpbios_encode_dma(p, &res->dma_resource[dma]);
711 			dma++;
712 			break;
713 
714 		case SMALL_TAG_PORT:
715 			if (len != 7)
716 				goto len_err;
717 			pnpbios_encode_port(p, &res->port_resource[port]);
718 			port++;
719 			break;
720 
721 		case SMALL_TAG_VENDOR:
722 			/* do nothing */
723 			break;
724 
725 		case SMALL_TAG_FIXEDPORT:
726 			if (len != 3)
727 				goto len_err;
728 			pnpbios_encode_fixed_port(p, &res->port_resource[port]);
729 			port++;
730 			break;
731 
732 		case SMALL_TAG_END:
733 			p = p + 2;
734         		return (unsigned char *)p;
735 			break;
736 
737 		default: /* an unkown tag */
738 			len_err:
739 			printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
740 			break;
741 		}
742 
743 		/* continue to the next tag */
744 		if (p[0] & LARGE_TAG)
745 			p += len + 3;
746 		else
747 			p += len + 1;
748 	}
749 
750 	printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
751 
752 	return NULL;
753 }
754 
755 
756 /*
757  * Core Parsing Functions
758  */
759 
760 int
761 pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node)
762 {
763 	unsigned char * p = (char *)node->data;
764 	unsigned char * end = (char *)(node->data + node->size);
765 	p = pnpbios_parse_allocated_resource_data(p,end,&dev->res);
766 	if (!p)
767 		return -EIO;
768 	p = pnpbios_parse_resource_option_data(p,end,dev);
769 	if (!p)
770 		return -EIO;
771 	p = pnpbios_parse_compatible_ids(p,end,dev);
772 	if (!p)
773 		return -EIO;
774 	return 0;
775 }
776 
777 int
778 pnpbios_read_resources_from_node(struct pnp_resource_table *res,
779 				 struct pnp_bios_node * node)
780 {
781 	unsigned char * p = (char *)node->data;
782 	unsigned char * end = (char *)(node->data + node->size);
783 	p = pnpbios_parse_allocated_resource_data(p,end,res);
784 	if (!p)
785 		return -EIO;
786 	return 0;
787 }
788 
789 int
790 pnpbios_write_resources_to_node(struct pnp_resource_table *res,
791 				struct pnp_bios_node * node)
792 {
793 	unsigned char * p = (char *)node->data;
794 	unsigned char * end = (char *)(node->data + node->size);
795 	p = pnpbios_encode_allocated_resource_data(p,end,res);
796 	if (!p)
797 		return -EIO;
798 	return 0;
799 }
800