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