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