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