811 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * rsparser.c - parses and encodes pnpbios resource data streams4 */5 6#include <linux/ctype.h>7#include <linux/pnp.h>8#include <linux/string.h>9 10#ifdef CONFIG_PCI11#include <linux/pci.h>12#else13inline 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 0x0123#define SMALL_TAG_LOGDEVID 0x0224#define SMALL_TAG_COMPATDEVID 0x0325#define SMALL_TAG_IRQ 0x0426#define SMALL_TAG_DMA 0x0527#define SMALL_TAG_STARTDEP 0x0628#define SMALL_TAG_ENDDEP 0x0729#define SMALL_TAG_PORT 0x0830#define SMALL_TAG_FIXEDPORT 0x0931#define SMALL_TAG_VENDOR 0x0e32#define SMALL_TAG_END 0x0f33#define LARGE_TAG 0x8034#define LARGE_TAG_MEM 0x8135#define LARGE_TAG_ANSISTR 0x8236#define LARGE_TAG_UNICODESTR 0x8337#define LARGE_TAG_VENDOR 0x8438#define LARGE_TAG_MEM32 0x8539#define LARGE_TAG_FIXEDMEM32 0x8640 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 Resources54 */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 else151 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 else205 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 Options215 */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 else419 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 IDs429 */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 memcpy(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 else489 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 Encoding499 */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 else590 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 else606 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_dev659 *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 else758 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 Functions768 */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}811