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