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