18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * rsparser.c - parses and encodes pnpbios resource data streams 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/ctype.h> 78c2ecf20Sopenharmony_ci#include <linux/pnp.h> 88c2ecf20Sopenharmony_ci#include <linux/string.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#else 138c2ecf20Sopenharmony_ciinline void pcibios_penalize_isa_irq(int irq, int active) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci} 168c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "../base.h" 198c2ecf20Sopenharmony_ci#include "pnpbios.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* standard resource tags */ 228c2ecf20Sopenharmony_ci#define SMALL_TAG_PNPVERNO 0x01 238c2ecf20Sopenharmony_ci#define SMALL_TAG_LOGDEVID 0x02 248c2ecf20Sopenharmony_ci#define SMALL_TAG_COMPATDEVID 0x03 258c2ecf20Sopenharmony_ci#define SMALL_TAG_IRQ 0x04 268c2ecf20Sopenharmony_ci#define SMALL_TAG_DMA 0x05 278c2ecf20Sopenharmony_ci#define SMALL_TAG_STARTDEP 0x06 288c2ecf20Sopenharmony_ci#define SMALL_TAG_ENDDEP 0x07 298c2ecf20Sopenharmony_ci#define SMALL_TAG_PORT 0x08 308c2ecf20Sopenharmony_ci#define SMALL_TAG_FIXEDPORT 0x09 318c2ecf20Sopenharmony_ci#define SMALL_TAG_VENDOR 0x0e 328c2ecf20Sopenharmony_ci#define SMALL_TAG_END 0x0f 338c2ecf20Sopenharmony_ci#define LARGE_TAG 0x80 348c2ecf20Sopenharmony_ci#define LARGE_TAG_MEM 0x81 358c2ecf20Sopenharmony_ci#define LARGE_TAG_ANSISTR 0x82 368c2ecf20Sopenharmony_ci#define LARGE_TAG_UNICODESTR 0x83 378c2ecf20Sopenharmony_ci#define LARGE_TAG_VENDOR 0x84 388c2ecf20Sopenharmony_ci#define LARGE_TAG_MEM32 0x85 398c2ecf20Sopenharmony_ci#define LARGE_TAG_FIXEDMEM32 0x86 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Resource Data Stream Format: 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Allocated Resources (required) 458c2ecf20Sopenharmony_ci * end tag -> 468c2ecf20Sopenharmony_ci * Resource Configuration Options (optional) 478c2ecf20Sopenharmony_ci * end tag -> 488c2ecf20Sopenharmony_ci * Compitable Device IDs (optional) 498c2ecf20Sopenharmony_ci * final end tag -> 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * Allocated Resources 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void pnpbios_parse_allocated_ioresource(struct pnp_dev *dev, 578c2ecf20Sopenharmony_ci int start, int len) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci int flags = 0; 608c2ecf20Sopenharmony_ci int end = start + len - 1; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (len <= 0 || end >= 0x10003) 638c2ecf20Sopenharmony_ci flags |= IORESOURCE_DISABLED; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci pnp_add_io_resource(dev, start, end, flags); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void pnpbios_parse_allocated_memresource(struct pnp_dev *dev, 698c2ecf20Sopenharmony_ci int start, int len) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int flags = 0; 728c2ecf20Sopenharmony_ci int end = start + len - 1; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (len <= 0) 758c2ecf20Sopenharmony_ci flags |= IORESOURCE_DISABLED; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci pnp_add_mem_resource(dev, start, end, flags); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev, 818c2ecf20Sopenharmony_ci unsigned char *p, 828c2ecf20Sopenharmony_ci unsigned char *end) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci unsigned int len, tag; 858c2ecf20Sopenharmony_ci int io, size, mask, i, flags; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (!p) 888c2ecf20Sopenharmony_ci return NULL; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "parse allocated resources\n"); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci pnp_init_resources(dev); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci while ((char *)p < (char *)end) { 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* determine the type of tag */ 978c2ecf20Sopenharmony_ci if (p[0] & LARGE_TAG) { /* large tag */ 988c2ecf20Sopenharmony_ci len = (p[2] << 8) | p[1]; 998c2ecf20Sopenharmony_ci tag = p[0]; 1008c2ecf20Sopenharmony_ci } else { /* small tag */ 1018c2ecf20Sopenharmony_ci len = p[0] & 0x07; 1028c2ecf20Sopenharmony_ci tag = ((p[0] >> 3) & 0x0f); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci switch (tag) { 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci case LARGE_TAG_MEM: 1088c2ecf20Sopenharmony_ci if (len != 9) 1098c2ecf20Sopenharmony_ci goto len_err; 1108c2ecf20Sopenharmony_ci io = *(short *)&p[4]; 1118c2ecf20Sopenharmony_ci size = *(short *)&p[10]; 1128c2ecf20Sopenharmony_ci pnpbios_parse_allocated_memresource(dev, io, size); 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci case LARGE_TAG_ANSISTR: 1168c2ecf20Sopenharmony_ci /* ignore this for now */ 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci case LARGE_TAG_VENDOR: 1208c2ecf20Sopenharmony_ci /* do nothing */ 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci case LARGE_TAG_MEM32: 1248c2ecf20Sopenharmony_ci if (len != 17) 1258c2ecf20Sopenharmony_ci goto len_err; 1268c2ecf20Sopenharmony_ci io = *(int *)&p[4]; 1278c2ecf20Sopenharmony_ci size = *(int *)&p[16]; 1288c2ecf20Sopenharmony_ci pnpbios_parse_allocated_memresource(dev, io, size); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci case LARGE_TAG_FIXEDMEM32: 1328c2ecf20Sopenharmony_ci if (len != 9) 1338c2ecf20Sopenharmony_ci goto len_err; 1348c2ecf20Sopenharmony_ci io = *(int *)&p[4]; 1358c2ecf20Sopenharmony_ci size = *(int *)&p[8]; 1368c2ecf20Sopenharmony_ci pnpbios_parse_allocated_memresource(dev, io, size); 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci case SMALL_TAG_IRQ: 1408c2ecf20Sopenharmony_ci if (len < 2 || len > 3) 1418c2ecf20Sopenharmony_ci goto len_err; 1428c2ecf20Sopenharmony_ci flags = 0; 1438c2ecf20Sopenharmony_ci io = -1; 1448c2ecf20Sopenharmony_ci mask = p[1] + p[2] * 256; 1458c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++, mask = mask >> 1) 1468c2ecf20Sopenharmony_ci if (mask & 0x01) 1478c2ecf20Sopenharmony_ci io = i; 1488c2ecf20Sopenharmony_ci if (io != -1) 1498c2ecf20Sopenharmony_ci pcibios_penalize_isa_irq(io, 1); 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci flags = IORESOURCE_DISABLED; 1528c2ecf20Sopenharmony_ci pnp_add_irq_resource(dev, io, flags); 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci case SMALL_TAG_DMA: 1568c2ecf20Sopenharmony_ci if (len != 2) 1578c2ecf20Sopenharmony_ci goto len_err; 1588c2ecf20Sopenharmony_ci flags = 0; 1598c2ecf20Sopenharmony_ci io = -1; 1608c2ecf20Sopenharmony_ci mask = p[1]; 1618c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++, mask = mask >> 1) 1628c2ecf20Sopenharmony_ci if (mask & 0x01) 1638c2ecf20Sopenharmony_ci io = i; 1648c2ecf20Sopenharmony_ci if (io == -1) 1658c2ecf20Sopenharmony_ci flags = IORESOURCE_DISABLED; 1668c2ecf20Sopenharmony_ci pnp_add_dma_resource(dev, io, flags); 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci case SMALL_TAG_PORT: 1708c2ecf20Sopenharmony_ci if (len != 7) 1718c2ecf20Sopenharmony_ci goto len_err; 1728c2ecf20Sopenharmony_ci io = p[2] + p[3] * 256; 1738c2ecf20Sopenharmony_ci size = p[7]; 1748c2ecf20Sopenharmony_ci pnpbios_parse_allocated_ioresource(dev, io, size); 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci case SMALL_TAG_VENDOR: 1788c2ecf20Sopenharmony_ci /* do nothing */ 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci case SMALL_TAG_FIXEDPORT: 1828c2ecf20Sopenharmony_ci if (len != 3) 1838c2ecf20Sopenharmony_ci goto len_err; 1848c2ecf20Sopenharmony_ci io = p[1] + p[2] * 256; 1858c2ecf20Sopenharmony_ci size = p[3]; 1868c2ecf20Sopenharmony_ci pnpbios_parse_allocated_ioresource(dev, io, size); 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci case SMALL_TAG_END: 1908c2ecf20Sopenharmony_ci p = p + 2; 1918c2ecf20Sopenharmony_ci return (unsigned char *)p; 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci default: /* an unknown tag */ 1958c2ecf20Sopenharmony_cilen_err: 1968c2ecf20Sopenharmony_ci dev_err(&dev->dev, "unknown tag %#x length %d\n", 1978c2ecf20Sopenharmony_ci tag, len); 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* continue to the next tag */ 2028c2ecf20Sopenharmony_ci if (p[0] & LARGE_TAG) 2038c2ecf20Sopenharmony_ci p += len + 3; 2048c2ecf20Sopenharmony_ci else 2058c2ecf20Sopenharmony_ci p += len + 1; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci dev_err(&dev->dev, "no end tag in resource structure\n"); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return NULL; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* 2148c2ecf20Sopenharmony_ci * Resource Configuration Options 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic __init void pnpbios_parse_mem_option(struct pnp_dev *dev, 2188c2ecf20Sopenharmony_ci unsigned char *p, int size, 2198c2ecf20Sopenharmony_ci unsigned int option_flags) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci resource_size_t min, max, align, len; 2228c2ecf20Sopenharmony_ci unsigned char flags; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci min = ((p[5] << 8) | p[4]) << 8; 2258c2ecf20Sopenharmony_ci max = ((p[7] << 8) | p[6]) << 8; 2268c2ecf20Sopenharmony_ci align = (p[9] << 8) | p[8]; 2278c2ecf20Sopenharmony_ci len = ((p[11] << 8) | p[10]) << 8; 2288c2ecf20Sopenharmony_ci flags = p[3]; 2298c2ecf20Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, min, max, align, len, 2308c2ecf20Sopenharmony_ci flags); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic __init void pnpbios_parse_mem32_option(struct pnp_dev *dev, 2348c2ecf20Sopenharmony_ci unsigned char *p, int size, 2358c2ecf20Sopenharmony_ci unsigned int option_flags) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci resource_size_t min, max, align, len; 2388c2ecf20Sopenharmony_ci unsigned char flags; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; 2418c2ecf20Sopenharmony_ci max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; 2428c2ecf20Sopenharmony_ci align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; 2438c2ecf20Sopenharmony_ci len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; 2448c2ecf20Sopenharmony_ci flags = p[3]; 2458c2ecf20Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, min, max, align, len, 2468c2ecf20Sopenharmony_ci flags); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev, 2508c2ecf20Sopenharmony_ci unsigned char *p, int size, 2518c2ecf20Sopenharmony_ci unsigned int option_flags) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci resource_size_t base, len; 2548c2ecf20Sopenharmony_ci unsigned char flags; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; 2578c2ecf20Sopenharmony_ci len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; 2588c2ecf20Sopenharmony_ci flags = p[3]; 2598c2ecf20Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic __init void pnpbios_parse_irq_option(struct pnp_dev *dev, 2638c2ecf20Sopenharmony_ci unsigned char *p, int size, 2648c2ecf20Sopenharmony_ci unsigned int option_flags) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci unsigned long bits; 2678c2ecf20Sopenharmony_ci pnp_irq_mask_t map; 2688c2ecf20Sopenharmony_ci unsigned char flags = IORESOURCE_IRQ_HIGHEDGE; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci bits = (p[2] << 8) | p[1]; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci bitmap_zero(map.bits, PNP_IRQ_NR); 2738c2ecf20Sopenharmony_ci bitmap_copy(map.bits, &bits, 16); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (size > 2) 2768c2ecf20Sopenharmony_ci flags = p[3]; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci pnp_register_irq_resource(dev, option_flags, &map, flags); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic __init void pnpbios_parse_dma_option(struct pnp_dev *dev, 2828c2ecf20Sopenharmony_ci unsigned char *p, int size, 2838c2ecf20Sopenharmony_ci unsigned int option_flags) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci pnp_register_dma_resource(dev, option_flags, p[1], p[2]); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic __init void pnpbios_parse_port_option(struct pnp_dev *dev, 2898c2ecf20Sopenharmony_ci unsigned char *p, int size, 2908c2ecf20Sopenharmony_ci unsigned int option_flags) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci resource_size_t min, max, align, len; 2938c2ecf20Sopenharmony_ci unsigned char flags; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci min = (p[3] << 8) | p[2]; 2968c2ecf20Sopenharmony_ci max = (p[5] << 8) | p[4]; 2978c2ecf20Sopenharmony_ci align = p[6]; 2988c2ecf20Sopenharmony_ci len = p[7]; 2998c2ecf20Sopenharmony_ci flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0; 3008c2ecf20Sopenharmony_ci pnp_register_port_resource(dev, option_flags, min, max, align, len, 3018c2ecf20Sopenharmony_ci flags); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev, 3058c2ecf20Sopenharmony_ci unsigned char *p, int size, 3068c2ecf20Sopenharmony_ci unsigned int option_flags) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci resource_size_t base, len; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci base = (p[2] << 8) | p[1]; 3118c2ecf20Sopenharmony_ci len = p[3]; 3128c2ecf20Sopenharmony_ci pnp_register_port_resource(dev, option_flags, base, base, 0, len, 3138c2ecf20Sopenharmony_ci IORESOURCE_IO_FIXED); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic __init unsigned char * 3178c2ecf20Sopenharmony_cipnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, 3188c2ecf20Sopenharmony_ci struct pnp_dev *dev) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci unsigned int len, tag; 3218c2ecf20Sopenharmony_ci int priority; 3228c2ecf20Sopenharmony_ci unsigned int option_flags; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (!p) 3258c2ecf20Sopenharmony_ci return NULL; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "parse resource options\n"); 3288c2ecf20Sopenharmony_ci option_flags = 0; 3298c2ecf20Sopenharmony_ci while ((char *)p < (char *)end) { 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* determine the type of tag */ 3328c2ecf20Sopenharmony_ci if (p[0] & LARGE_TAG) { /* large tag */ 3338c2ecf20Sopenharmony_ci len = (p[2] << 8) | p[1]; 3348c2ecf20Sopenharmony_ci tag = p[0]; 3358c2ecf20Sopenharmony_ci } else { /* small tag */ 3368c2ecf20Sopenharmony_ci len = p[0] & 0x07; 3378c2ecf20Sopenharmony_ci tag = ((p[0] >> 3) & 0x0f); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci switch (tag) { 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci case LARGE_TAG_MEM: 3438c2ecf20Sopenharmony_ci if (len != 9) 3448c2ecf20Sopenharmony_ci goto len_err; 3458c2ecf20Sopenharmony_ci pnpbios_parse_mem_option(dev, p, len, option_flags); 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci case LARGE_TAG_MEM32: 3498c2ecf20Sopenharmony_ci if (len != 17) 3508c2ecf20Sopenharmony_ci goto len_err; 3518c2ecf20Sopenharmony_ci pnpbios_parse_mem32_option(dev, p, len, option_flags); 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci case LARGE_TAG_FIXEDMEM32: 3558c2ecf20Sopenharmony_ci if (len != 9) 3568c2ecf20Sopenharmony_ci goto len_err; 3578c2ecf20Sopenharmony_ci pnpbios_parse_fixed_mem32_option(dev, p, len, 3588c2ecf20Sopenharmony_ci option_flags); 3598c2ecf20Sopenharmony_ci break; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci case SMALL_TAG_IRQ: 3628c2ecf20Sopenharmony_ci if (len < 2 || len > 3) 3638c2ecf20Sopenharmony_ci goto len_err; 3648c2ecf20Sopenharmony_ci pnpbios_parse_irq_option(dev, p, len, option_flags); 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci case SMALL_TAG_DMA: 3688c2ecf20Sopenharmony_ci if (len != 2) 3698c2ecf20Sopenharmony_ci goto len_err; 3708c2ecf20Sopenharmony_ci pnpbios_parse_dma_option(dev, p, len, option_flags); 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci case SMALL_TAG_PORT: 3748c2ecf20Sopenharmony_ci if (len != 7) 3758c2ecf20Sopenharmony_ci goto len_err; 3768c2ecf20Sopenharmony_ci pnpbios_parse_port_option(dev, p, len, option_flags); 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci case SMALL_TAG_VENDOR: 3808c2ecf20Sopenharmony_ci /* do nothing */ 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci case SMALL_TAG_FIXEDPORT: 3848c2ecf20Sopenharmony_ci if (len != 3) 3858c2ecf20Sopenharmony_ci goto len_err; 3868c2ecf20Sopenharmony_ci pnpbios_parse_fixed_port_option(dev, p, len, 3878c2ecf20Sopenharmony_ci option_flags); 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci case SMALL_TAG_STARTDEP: 3918c2ecf20Sopenharmony_ci if (len > 1) 3928c2ecf20Sopenharmony_ci goto len_err; 3938c2ecf20Sopenharmony_ci priority = PNP_RES_PRIORITY_ACCEPTABLE; 3948c2ecf20Sopenharmony_ci if (len > 0) 3958c2ecf20Sopenharmony_ci priority = p[1]; 3968c2ecf20Sopenharmony_ci option_flags = pnp_new_dependent_set(dev, priority); 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci case SMALL_TAG_ENDDEP: 4008c2ecf20Sopenharmony_ci if (len != 0) 4018c2ecf20Sopenharmony_ci goto len_err; 4028c2ecf20Sopenharmony_ci option_flags = 0; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci case SMALL_TAG_END: 4068c2ecf20Sopenharmony_ci return p + 2; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci default: /* an unknown tag */ 4098c2ecf20Sopenharmony_cilen_err: 4108c2ecf20Sopenharmony_ci dev_err(&dev->dev, "unknown tag %#x length %d\n", 4118c2ecf20Sopenharmony_ci tag, len); 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* continue to the next tag */ 4168c2ecf20Sopenharmony_ci if (p[0] & LARGE_TAG) 4178c2ecf20Sopenharmony_ci p += len + 3; 4188c2ecf20Sopenharmony_ci else 4198c2ecf20Sopenharmony_ci p += len + 1; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci dev_err(&dev->dev, "no end tag in resource structure\n"); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return NULL; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* 4288c2ecf20Sopenharmony_ci * Compatible Device IDs 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic unsigned char *pnpbios_parse_compatible_ids(unsigned char *p, 4328c2ecf20Sopenharmony_ci unsigned char *end, 4338c2ecf20Sopenharmony_ci struct pnp_dev *dev) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci int len, tag; 4368c2ecf20Sopenharmony_ci u32 eisa_id; 4378c2ecf20Sopenharmony_ci char id[8]; 4388c2ecf20Sopenharmony_ci struct pnp_id *dev_id; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (!p) 4418c2ecf20Sopenharmony_ci return NULL; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci while ((char *)p < (char *)end) { 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* determine the type of tag */ 4468c2ecf20Sopenharmony_ci if (p[0] & LARGE_TAG) { /* large tag */ 4478c2ecf20Sopenharmony_ci len = (p[2] << 8) | p[1]; 4488c2ecf20Sopenharmony_ci tag = p[0]; 4498c2ecf20Sopenharmony_ci } else { /* small tag */ 4508c2ecf20Sopenharmony_ci len = p[0] & 0x07; 4518c2ecf20Sopenharmony_ci tag = ((p[0] >> 3) & 0x0f); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci switch (tag) { 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci case LARGE_TAG_ANSISTR: 4578c2ecf20Sopenharmony_ci strncpy(dev->name, p + 3, 4588c2ecf20Sopenharmony_ci len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len); 4598c2ecf20Sopenharmony_ci dev->name[len >= 4608c2ecf20Sopenharmony_ci PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0'; 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci case SMALL_TAG_COMPATDEVID: /* compatible ID */ 4648c2ecf20Sopenharmony_ci if (len != 4) 4658c2ecf20Sopenharmony_ci goto len_err; 4668c2ecf20Sopenharmony_ci eisa_id = p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24; 4678c2ecf20Sopenharmony_ci pnp_eisa_id_to_string(eisa_id & PNP_EISA_ID_MASK, id); 4688c2ecf20Sopenharmony_ci dev_id = pnp_add_id(dev, id); 4698c2ecf20Sopenharmony_ci if (!dev_id) 4708c2ecf20Sopenharmony_ci return NULL; 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci case SMALL_TAG_END: 4748c2ecf20Sopenharmony_ci p = p + 2; 4758c2ecf20Sopenharmony_ci return (unsigned char *)p; 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci default: /* an unknown tag */ 4798c2ecf20Sopenharmony_cilen_err: 4808c2ecf20Sopenharmony_ci dev_err(&dev->dev, "unknown tag %#x length %d\n", 4818c2ecf20Sopenharmony_ci tag, len); 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* continue to the next tag */ 4868c2ecf20Sopenharmony_ci if (p[0] & LARGE_TAG) 4878c2ecf20Sopenharmony_ci p += len + 3; 4888c2ecf20Sopenharmony_ci else 4898c2ecf20Sopenharmony_ci p += len + 1; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci dev_err(&dev->dev, "no end tag in resource structure\n"); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return NULL; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* 4988c2ecf20Sopenharmony_ci * Allocated Resource Encoding 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p, 5028c2ecf20Sopenharmony_ci struct resource *res) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci unsigned long base; 5058c2ecf20Sopenharmony_ci unsigned long len; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (pnp_resource_enabled(res)) { 5088c2ecf20Sopenharmony_ci base = res->start; 5098c2ecf20Sopenharmony_ci len = resource_size(res); 5108c2ecf20Sopenharmony_ci } else { 5118c2ecf20Sopenharmony_ci base = 0; 5128c2ecf20Sopenharmony_ci len = 0; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci p[4] = (base >> 8) & 0xff; 5168c2ecf20Sopenharmony_ci p[5] = ((base >> 8) >> 8) & 0xff; 5178c2ecf20Sopenharmony_ci p[6] = (base >> 8) & 0xff; 5188c2ecf20Sopenharmony_ci p[7] = ((base >> 8) >> 8) & 0xff; 5198c2ecf20Sopenharmony_ci p[10] = (len >> 8) & 0xff; 5208c2ecf20Sopenharmony_ci p[11] = ((len >> 8) >> 8) & 0xff; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode mem %#lx-%#lx\n", base, base + len - 1); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p, 5268c2ecf20Sopenharmony_ci struct resource *res) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci unsigned long base; 5298c2ecf20Sopenharmony_ci unsigned long len; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (pnp_resource_enabled(res)) { 5328c2ecf20Sopenharmony_ci base = res->start; 5338c2ecf20Sopenharmony_ci len = resource_size(res); 5348c2ecf20Sopenharmony_ci } else { 5358c2ecf20Sopenharmony_ci base = 0; 5368c2ecf20Sopenharmony_ci len = 0; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci p[4] = base & 0xff; 5408c2ecf20Sopenharmony_ci p[5] = (base >> 8) & 0xff; 5418c2ecf20Sopenharmony_ci p[6] = (base >> 16) & 0xff; 5428c2ecf20Sopenharmony_ci p[7] = (base >> 24) & 0xff; 5438c2ecf20Sopenharmony_ci p[8] = base & 0xff; 5448c2ecf20Sopenharmony_ci p[9] = (base >> 8) & 0xff; 5458c2ecf20Sopenharmony_ci p[10] = (base >> 16) & 0xff; 5468c2ecf20Sopenharmony_ci p[11] = (base >> 24) & 0xff; 5478c2ecf20Sopenharmony_ci p[16] = len & 0xff; 5488c2ecf20Sopenharmony_ci p[17] = (len >> 8) & 0xff; 5498c2ecf20Sopenharmony_ci p[18] = (len >> 16) & 0xff; 5508c2ecf20Sopenharmony_ci p[19] = (len >> 24) & 0xff; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode mem32 %#lx-%#lx\n", base, base + len - 1); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p, 5568c2ecf20Sopenharmony_ci struct resource *res) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci unsigned long base; 5598c2ecf20Sopenharmony_ci unsigned long len; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (pnp_resource_enabled(res)) { 5628c2ecf20Sopenharmony_ci base = res->start; 5638c2ecf20Sopenharmony_ci len = resource_size(res); 5648c2ecf20Sopenharmony_ci } else { 5658c2ecf20Sopenharmony_ci base = 0; 5668c2ecf20Sopenharmony_ci len = 0; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci p[4] = base & 0xff; 5708c2ecf20Sopenharmony_ci p[5] = (base >> 8) & 0xff; 5718c2ecf20Sopenharmony_ci p[6] = (base >> 16) & 0xff; 5728c2ecf20Sopenharmony_ci p[7] = (base >> 24) & 0xff; 5738c2ecf20Sopenharmony_ci p[8] = len & 0xff; 5748c2ecf20Sopenharmony_ci p[9] = (len >> 8) & 0xff; 5758c2ecf20Sopenharmony_ci p[10] = (len >> 16) & 0xff; 5768c2ecf20Sopenharmony_ci p[11] = (len >> 24) & 0xff; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode fixed_mem32 %#lx-%#lx\n", base, 5798c2ecf20Sopenharmony_ci base + len - 1); 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p, 5838c2ecf20Sopenharmony_ci struct resource *res) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci unsigned long map; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (pnp_resource_enabled(res)) 5888c2ecf20Sopenharmony_ci map = 1 << res->start; 5898c2ecf20Sopenharmony_ci else 5908c2ecf20Sopenharmony_ci map = 0; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci p[1] = map & 0xff; 5938c2ecf20Sopenharmony_ci p[2] = (map >> 8) & 0xff; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode irq mask %#lx\n", map); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p, 5998c2ecf20Sopenharmony_ci struct resource *res) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci unsigned long map; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (pnp_resource_enabled(res)) 6048c2ecf20Sopenharmony_ci map = 1 << res->start; 6058c2ecf20Sopenharmony_ci else 6068c2ecf20Sopenharmony_ci map = 0; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci p[1] = map & 0xff; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode dma mask %#lx\n", map); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p, 6148c2ecf20Sopenharmony_ci struct resource *res) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci unsigned long base; 6178c2ecf20Sopenharmony_ci unsigned long len; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (pnp_resource_enabled(res)) { 6208c2ecf20Sopenharmony_ci base = res->start; 6218c2ecf20Sopenharmony_ci len = resource_size(res); 6228c2ecf20Sopenharmony_ci } else { 6238c2ecf20Sopenharmony_ci base = 0; 6248c2ecf20Sopenharmony_ci len = 0; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci p[2] = base & 0xff; 6288c2ecf20Sopenharmony_ci p[3] = (base >> 8) & 0xff; 6298c2ecf20Sopenharmony_ci p[4] = base & 0xff; 6308c2ecf20Sopenharmony_ci p[5] = (base >> 8) & 0xff; 6318c2ecf20Sopenharmony_ci p[7] = len & 0xff; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode io %#lx-%#lx\n", base, base + len - 1); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p, 6378c2ecf20Sopenharmony_ci struct resource *res) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci unsigned long base = res->start; 6408c2ecf20Sopenharmony_ci unsigned long len = resource_size(res); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (pnp_resource_enabled(res)) { 6438c2ecf20Sopenharmony_ci base = res->start; 6448c2ecf20Sopenharmony_ci len = resource_size(res); 6458c2ecf20Sopenharmony_ci } else { 6468c2ecf20Sopenharmony_ci base = 0; 6478c2ecf20Sopenharmony_ci len = 0; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci p[1] = base & 0xff; 6518c2ecf20Sopenharmony_ci p[2] = (base >> 8) & 0xff; 6528c2ecf20Sopenharmony_ci p[3] = len & 0xff; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode fixed_io %#lx-%#lx\n", base, 6558c2ecf20Sopenharmony_ci base + len - 1); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev 6598c2ecf20Sopenharmony_ci *dev, 6608c2ecf20Sopenharmony_ci unsigned char *p, 6618c2ecf20Sopenharmony_ci unsigned char *end) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci unsigned int len, tag; 6648c2ecf20Sopenharmony_ci int port = 0, irq = 0, dma = 0, mem = 0; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (!p) 6678c2ecf20Sopenharmony_ci return NULL; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci while ((char *)p < (char *)end) { 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* determine the type of tag */ 6728c2ecf20Sopenharmony_ci if (p[0] & LARGE_TAG) { /* large tag */ 6738c2ecf20Sopenharmony_ci len = (p[2] << 8) | p[1]; 6748c2ecf20Sopenharmony_ci tag = p[0]; 6758c2ecf20Sopenharmony_ci } else { /* small tag */ 6768c2ecf20Sopenharmony_ci len = p[0] & 0x07; 6778c2ecf20Sopenharmony_ci tag = ((p[0] >> 3) & 0x0f); 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci switch (tag) { 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci case LARGE_TAG_MEM: 6838c2ecf20Sopenharmony_ci if (len != 9) 6848c2ecf20Sopenharmony_ci goto len_err; 6858c2ecf20Sopenharmony_ci pnpbios_encode_mem(dev, p, 6868c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 6878c2ecf20Sopenharmony_ci mem++; 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci case LARGE_TAG_MEM32: 6918c2ecf20Sopenharmony_ci if (len != 17) 6928c2ecf20Sopenharmony_ci goto len_err; 6938c2ecf20Sopenharmony_ci pnpbios_encode_mem32(dev, p, 6948c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 6958c2ecf20Sopenharmony_ci mem++; 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci case LARGE_TAG_FIXEDMEM32: 6998c2ecf20Sopenharmony_ci if (len != 9) 7008c2ecf20Sopenharmony_ci goto len_err; 7018c2ecf20Sopenharmony_ci pnpbios_encode_fixed_mem32(dev, p, 7028c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 7038c2ecf20Sopenharmony_ci mem++; 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci case SMALL_TAG_IRQ: 7078c2ecf20Sopenharmony_ci if (len < 2 || len > 3) 7088c2ecf20Sopenharmony_ci goto len_err; 7098c2ecf20Sopenharmony_ci pnpbios_encode_irq(dev, p, 7108c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IRQ, irq)); 7118c2ecf20Sopenharmony_ci irq++; 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci case SMALL_TAG_DMA: 7158c2ecf20Sopenharmony_ci if (len != 2) 7168c2ecf20Sopenharmony_ci goto len_err; 7178c2ecf20Sopenharmony_ci pnpbios_encode_dma(dev, p, 7188c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_DMA, dma)); 7198c2ecf20Sopenharmony_ci dma++; 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci case SMALL_TAG_PORT: 7238c2ecf20Sopenharmony_ci if (len != 7) 7248c2ecf20Sopenharmony_ci goto len_err; 7258c2ecf20Sopenharmony_ci pnpbios_encode_port(dev, p, 7268c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IO, port)); 7278c2ecf20Sopenharmony_ci port++; 7288c2ecf20Sopenharmony_ci break; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci case SMALL_TAG_VENDOR: 7318c2ecf20Sopenharmony_ci /* do nothing */ 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci case SMALL_TAG_FIXEDPORT: 7358c2ecf20Sopenharmony_ci if (len != 3) 7368c2ecf20Sopenharmony_ci goto len_err; 7378c2ecf20Sopenharmony_ci pnpbios_encode_fixed_port(dev, p, 7388c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IO, port)); 7398c2ecf20Sopenharmony_ci port++; 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci case SMALL_TAG_END: 7438c2ecf20Sopenharmony_ci p = p + 2; 7448c2ecf20Sopenharmony_ci return (unsigned char *)p; 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci default: /* an unknown tag */ 7488c2ecf20Sopenharmony_cilen_err: 7498c2ecf20Sopenharmony_ci dev_err(&dev->dev, "unknown tag %#x length %d\n", 7508c2ecf20Sopenharmony_ci tag, len); 7518c2ecf20Sopenharmony_ci break; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* continue to the next tag */ 7558c2ecf20Sopenharmony_ci if (p[0] & LARGE_TAG) 7568c2ecf20Sopenharmony_ci p += len + 3; 7578c2ecf20Sopenharmony_ci else 7588c2ecf20Sopenharmony_ci p += len + 1; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci dev_err(&dev->dev, "no end tag in resource structure\n"); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return NULL; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/* 7678c2ecf20Sopenharmony_ci * Core Parsing Functions 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ciint __init pnpbios_parse_data_stream(struct pnp_dev *dev, 7718c2ecf20Sopenharmony_ci struct pnp_bios_node *node) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci unsigned char *p = (char *)node->data; 7748c2ecf20Sopenharmony_ci unsigned char *end = (char *)(node->data + node->size); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci p = pnpbios_parse_allocated_resource_data(dev, p, end); 7778c2ecf20Sopenharmony_ci if (!p) 7788c2ecf20Sopenharmony_ci return -EIO; 7798c2ecf20Sopenharmony_ci p = pnpbios_parse_resource_option_data(p, end, dev); 7808c2ecf20Sopenharmony_ci if (!p) 7818c2ecf20Sopenharmony_ci return -EIO; 7828c2ecf20Sopenharmony_ci p = pnpbios_parse_compatible_ids(p, end, dev); 7838c2ecf20Sopenharmony_ci if (!p) 7848c2ecf20Sopenharmony_ci return -EIO; 7858c2ecf20Sopenharmony_ci return 0; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ciint pnpbios_read_resources_from_node(struct pnp_dev *dev, 7898c2ecf20Sopenharmony_ci struct pnp_bios_node *node) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci unsigned char *p = (char *)node->data; 7928c2ecf20Sopenharmony_ci unsigned char *end = (char *)(node->data + node->size); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci p = pnpbios_parse_allocated_resource_data(dev, p, end); 7958c2ecf20Sopenharmony_ci if (!p) 7968c2ecf20Sopenharmony_ci return -EIO; 7978c2ecf20Sopenharmony_ci return 0; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ciint pnpbios_write_resources_to_node(struct pnp_dev *dev, 8018c2ecf20Sopenharmony_ci struct pnp_bios_node *node) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci unsigned char *p = (char *)node->data; 8048c2ecf20Sopenharmony_ci unsigned char *end = (char *)(node->data + node->size); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci p = pnpbios_encode_allocated_resource_data(dev, p, end); 8078c2ecf20Sopenharmony_ci if (!p) 8088c2ecf20Sopenharmony_ci return -EIO; 8098c2ecf20Sopenharmony_ci return 0; 8108c2ecf20Sopenharmony_ci} 811