162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * rsparser.c - parses and encodes pnpbios resource data streams
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/ctype.h>
762306a36Sopenharmony_ci#include <linux/pnp.h>
862306a36Sopenharmony_ci#include <linux/string.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifdef CONFIG_PCI
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#else
1362306a36Sopenharmony_ciinline void pcibios_penalize_isa_irq(int irq, int active)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci}
1662306a36Sopenharmony_ci#endif				/* CONFIG_PCI */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "../base.h"
1962306a36Sopenharmony_ci#include "pnpbios.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* standard resource tags */
2262306a36Sopenharmony_ci#define SMALL_TAG_PNPVERNO		0x01
2362306a36Sopenharmony_ci#define SMALL_TAG_LOGDEVID		0x02
2462306a36Sopenharmony_ci#define SMALL_TAG_COMPATDEVID		0x03
2562306a36Sopenharmony_ci#define SMALL_TAG_IRQ			0x04
2662306a36Sopenharmony_ci#define SMALL_TAG_DMA			0x05
2762306a36Sopenharmony_ci#define SMALL_TAG_STARTDEP		0x06
2862306a36Sopenharmony_ci#define SMALL_TAG_ENDDEP		0x07
2962306a36Sopenharmony_ci#define SMALL_TAG_PORT			0x08
3062306a36Sopenharmony_ci#define SMALL_TAG_FIXEDPORT		0x09
3162306a36Sopenharmony_ci#define SMALL_TAG_VENDOR		0x0e
3262306a36Sopenharmony_ci#define SMALL_TAG_END			0x0f
3362306a36Sopenharmony_ci#define LARGE_TAG			0x80
3462306a36Sopenharmony_ci#define LARGE_TAG_MEM			0x81
3562306a36Sopenharmony_ci#define LARGE_TAG_ANSISTR		0x82
3662306a36Sopenharmony_ci#define LARGE_TAG_UNICODESTR		0x83
3762306a36Sopenharmony_ci#define LARGE_TAG_VENDOR		0x84
3862306a36Sopenharmony_ci#define LARGE_TAG_MEM32			0x85
3962306a36Sopenharmony_ci#define LARGE_TAG_FIXEDMEM32		0x86
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * Resource Data Stream Format:
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Allocated Resources (required)
4562306a36Sopenharmony_ci * end tag ->
4662306a36Sopenharmony_ci * Resource Configuration Options (optional)
4762306a36Sopenharmony_ci * end tag ->
4862306a36Sopenharmony_ci * Compitable Device IDs (optional)
4962306a36Sopenharmony_ci * final end tag ->
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/*
5362306a36Sopenharmony_ci * Allocated Resources
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic void pnpbios_parse_allocated_ioresource(struct pnp_dev *dev,
5762306a36Sopenharmony_ci					       int start, int len)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	int flags = 0;
6062306a36Sopenharmony_ci	int end = start + len - 1;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (len <= 0 || end >= 0x10003)
6362306a36Sopenharmony_ci		flags |= IORESOURCE_DISABLED;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	pnp_add_io_resource(dev, start, end, flags);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic void pnpbios_parse_allocated_memresource(struct pnp_dev *dev,
6962306a36Sopenharmony_ci						int start, int len)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	int flags = 0;
7262306a36Sopenharmony_ci	int end = start + len - 1;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (len <= 0)
7562306a36Sopenharmony_ci		flags |= IORESOURCE_DISABLED;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	pnp_add_mem_resource(dev, start, end, flags);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev,
8162306a36Sopenharmony_ci							    unsigned char *p,
8262306a36Sopenharmony_ci							    unsigned char *end)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	unsigned int len, tag;
8562306a36Sopenharmony_ci	int io, size, mask, i, flags;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (!p)
8862306a36Sopenharmony_ci		return NULL;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "parse allocated resources\n");
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	pnp_init_resources(dev);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	while ((char *)p < (char *)end) {
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		/* determine the type of tag */
9762306a36Sopenharmony_ci		if (p[0] & LARGE_TAG) {	/* large tag */
9862306a36Sopenharmony_ci			len = (p[2] << 8) | p[1];
9962306a36Sopenharmony_ci			tag = p[0];
10062306a36Sopenharmony_ci		} else {	/* small tag */
10162306a36Sopenharmony_ci			len = p[0] & 0x07;
10262306a36Sopenharmony_ci			tag = ((p[0] >> 3) & 0x0f);
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		switch (tag) {
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci		case LARGE_TAG_MEM:
10862306a36Sopenharmony_ci			if (len != 9)
10962306a36Sopenharmony_ci				goto len_err;
11062306a36Sopenharmony_ci			io = *(short *)&p[4];
11162306a36Sopenharmony_ci			size = *(short *)&p[10];
11262306a36Sopenharmony_ci			pnpbios_parse_allocated_memresource(dev, io, size);
11362306a36Sopenharmony_ci			break;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		case LARGE_TAG_ANSISTR:
11662306a36Sopenharmony_ci			/* ignore this for now */
11762306a36Sopenharmony_ci			break;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		case LARGE_TAG_VENDOR:
12062306a36Sopenharmony_ci			/* do nothing */
12162306a36Sopenharmony_ci			break;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		case LARGE_TAG_MEM32:
12462306a36Sopenharmony_ci			if (len != 17)
12562306a36Sopenharmony_ci				goto len_err;
12662306a36Sopenharmony_ci			io = *(int *)&p[4];
12762306a36Sopenharmony_ci			size = *(int *)&p[16];
12862306a36Sopenharmony_ci			pnpbios_parse_allocated_memresource(dev, io, size);
12962306a36Sopenharmony_ci			break;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		case LARGE_TAG_FIXEDMEM32:
13262306a36Sopenharmony_ci			if (len != 9)
13362306a36Sopenharmony_ci				goto len_err;
13462306a36Sopenharmony_ci			io = *(int *)&p[4];
13562306a36Sopenharmony_ci			size = *(int *)&p[8];
13662306a36Sopenharmony_ci			pnpbios_parse_allocated_memresource(dev, io, size);
13762306a36Sopenharmony_ci			break;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		case SMALL_TAG_IRQ:
14062306a36Sopenharmony_ci			if (len < 2 || len > 3)
14162306a36Sopenharmony_ci				goto len_err;
14262306a36Sopenharmony_ci			flags = 0;
14362306a36Sopenharmony_ci			io = -1;
14462306a36Sopenharmony_ci			mask = p[1] + p[2] * 256;
14562306a36Sopenharmony_ci			for (i = 0; i < 16; i++, mask = mask >> 1)
14662306a36Sopenharmony_ci				if (mask & 0x01)
14762306a36Sopenharmony_ci					io = i;
14862306a36Sopenharmony_ci			if (io != -1)
14962306a36Sopenharmony_ci				pcibios_penalize_isa_irq(io, 1);
15062306a36Sopenharmony_ci			else
15162306a36Sopenharmony_ci				flags = IORESOURCE_DISABLED;
15262306a36Sopenharmony_ci			pnp_add_irq_resource(dev, io, flags);
15362306a36Sopenharmony_ci			break;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		case SMALL_TAG_DMA:
15662306a36Sopenharmony_ci			if (len != 2)
15762306a36Sopenharmony_ci				goto len_err;
15862306a36Sopenharmony_ci			flags = 0;
15962306a36Sopenharmony_ci			io = -1;
16062306a36Sopenharmony_ci			mask = p[1];
16162306a36Sopenharmony_ci			for (i = 0; i < 8; i++, mask = mask >> 1)
16262306a36Sopenharmony_ci				if (mask & 0x01)
16362306a36Sopenharmony_ci					io = i;
16462306a36Sopenharmony_ci			if (io == -1)
16562306a36Sopenharmony_ci				flags = IORESOURCE_DISABLED;
16662306a36Sopenharmony_ci			pnp_add_dma_resource(dev, io, flags);
16762306a36Sopenharmony_ci			break;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		case SMALL_TAG_PORT:
17062306a36Sopenharmony_ci			if (len != 7)
17162306a36Sopenharmony_ci				goto len_err;
17262306a36Sopenharmony_ci			io = p[2] + p[3] * 256;
17362306a36Sopenharmony_ci			size = p[7];
17462306a36Sopenharmony_ci			pnpbios_parse_allocated_ioresource(dev, io, size);
17562306a36Sopenharmony_ci			break;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		case SMALL_TAG_VENDOR:
17862306a36Sopenharmony_ci			/* do nothing */
17962306a36Sopenharmony_ci			break;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		case SMALL_TAG_FIXEDPORT:
18262306a36Sopenharmony_ci			if (len != 3)
18362306a36Sopenharmony_ci				goto len_err;
18462306a36Sopenharmony_ci			io = p[1] + p[2] * 256;
18562306a36Sopenharmony_ci			size = p[3];
18662306a36Sopenharmony_ci			pnpbios_parse_allocated_ioresource(dev, io, size);
18762306a36Sopenharmony_ci			break;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		case SMALL_TAG_END:
19062306a36Sopenharmony_ci			p = p + 2;
19162306a36Sopenharmony_ci			return (unsigned char *)p;
19262306a36Sopenharmony_ci			break;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		default:	/* an unknown tag */
19562306a36Sopenharmony_cilen_err:
19662306a36Sopenharmony_ci			dev_err(&dev->dev, "unknown tag %#x length %d\n",
19762306a36Sopenharmony_ci				tag, len);
19862306a36Sopenharmony_ci			break;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		/* continue to the next tag */
20262306a36Sopenharmony_ci		if (p[0] & LARGE_TAG)
20362306a36Sopenharmony_ci			p += len + 3;
20462306a36Sopenharmony_ci		else
20562306a36Sopenharmony_ci			p += len + 1;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	dev_err(&dev->dev, "no end tag in resource structure\n");
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	return NULL;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/*
21462306a36Sopenharmony_ci * Resource Configuration Options
21562306a36Sopenharmony_ci */
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic __init void pnpbios_parse_mem_option(struct pnp_dev *dev,
21862306a36Sopenharmony_ci					    unsigned char *p, int size,
21962306a36Sopenharmony_ci					    unsigned int option_flags)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	resource_size_t min, max, align, len;
22262306a36Sopenharmony_ci	unsigned char flags;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	min = ((p[5] << 8) | p[4]) << 8;
22562306a36Sopenharmony_ci	max = ((p[7] << 8) | p[6]) << 8;
22662306a36Sopenharmony_ci	align = (p[9] << 8) | p[8];
22762306a36Sopenharmony_ci	len = ((p[11] << 8) | p[10]) << 8;
22862306a36Sopenharmony_ci	flags = p[3];
22962306a36Sopenharmony_ci	pnp_register_mem_resource(dev, option_flags, min, max, align, len,
23062306a36Sopenharmony_ci				  flags);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic __init void pnpbios_parse_mem32_option(struct pnp_dev *dev,
23462306a36Sopenharmony_ci					      unsigned char *p, int size,
23562306a36Sopenharmony_ci					      unsigned int option_flags)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	resource_size_t min, max, align, len;
23862306a36Sopenharmony_ci	unsigned char flags;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
24162306a36Sopenharmony_ci	max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
24262306a36Sopenharmony_ci	align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
24362306a36Sopenharmony_ci	len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
24462306a36Sopenharmony_ci	flags = p[3];
24562306a36Sopenharmony_ci	pnp_register_mem_resource(dev, option_flags, min, max, align, len,
24662306a36Sopenharmony_ci				  flags);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev,
25062306a36Sopenharmony_ci						    unsigned char *p, int size,
25162306a36Sopenharmony_ci						    unsigned int option_flags)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	resource_size_t base, len;
25462306a36Sopenharmony_ci	unsigned char flags;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
25762306a36Sopenharmony_ci	len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
25862306a36Sopenharmony_ci	flags = p[3];
25962306a36Sopenharmony_ci	pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic __init void pnpbios_parse_irq_option(struct pnp_dev *dev,
26362306a36Sopenharmony_ci					    unsigned char *p, int size,
26462306a36Sopenharmony_ci					    unsigned int option_flags)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	unsigned long bits;
26762306a36Sopenharmony_ci	pnp_irq_mask_t map;
26862306a36Sopenharmony_ci	unsigned char flags = IORESOURCE_IRQ_HIGHEDGE;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	bits = (p[2] << 8) | p[1];
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	bitmap_zero(map.bits, PNP_IRQ_NR);
27362306a36Sopenharmony_ci	bitmap_copy(map.bits, &bits, 16);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (size > 2)
27662306a36Sopenharmony_ci		flags = p[3];
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	pnp_register_irq_resource(dev, option_flags, &map, flags);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic __init void pnpbios_parse_dma_option(struct pnp_dev *dev,
28262306a36Sopenharmony_ci					    unsigned char *p, int size,
28362306a36Sopenharmony_ci					    unsigned int option_flags)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	pnp_register_dma_resource(dev, option_flags, p[1], p[2]);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic __init void pnpbios_parse_port_option(struct pnp_dev *dev,
28962306a36Sopenharmony_ci					     unsigned char *p, int size,
29062306a36Sopenharmony_ci					     unsigned int option_flags)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	resource_size_t min, max, align, len;
29362306a36Sopenharmony_ci	unsigned char flags;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	min = (p[3] << 8) | p[2];
29662306a36Sopenharmony_ci	max = (p[5] << 8) | p[4];
29762306a36Sopenharmony_ci	align = p[6];
29862306a36Sopenharmony_ci	len = p[7];
29962306a36Sopenharmony_ci	flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0;
30062306a36Sopenharmony_ci	pnp_register_port_resource(dev, option_flags, min, max, align, len,
30162306a36Sopenharmony_ci				   flags);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev,
30562306a36Sopenharmony_ci						   unsigned char *p, int size,
30662306a36Sopenharmony_ci						   unsigned int option_flags)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	resource_size_t base, len;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	base = (p[2] << 8) | p[1];
31162306a36Sopenharmony_ci	len = p[3];
31262306a36Sopenharmony_ci	pnp_register_port_resource(dev, option_flags, base, base, 0, len,
31362306a36Sopenharmony_ci				   IORESOURCE_IO_FIXED);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic __init unsigned char *
31762306a36Sopenharmony_cipnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
31862306a36Sopenharmony_ci				   struct pnp_dev *dev)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	unsigned int len, tag;
32162306a36Sopenharmony_ci	int priority;
32262306a36Sopenharmony_ci	unsigned int option_flags;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (!p)
32562306a36Sopenharmony_ci		return NULL;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "parse resource options\n");
32862306a36Sopenharmony_ci	option_flags = 0;
32962306a36Sopenharmony_ci	while ((char *)p < (char *)end) {
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		/* determine the type of tag */
33262306a36Sopenharmony_ci		if (p[0] & LARGE_TAG) {	/* large tag */
33362306a36Sopenharmony_ci			len = (p[2] << 8) | p[1];
33462306a36Sopenharmony_ci			tag = p[0];
33562306a36Sopenharmony_ci		} else {	/* small tag */
33662306a36Sopenharmony_ci			len = p[0] & 0x07;
33762306a36Sopenharmony_ci			tag = ((p[0] >> 3) & 0x0f);
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		switch (tag) {
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		case LARGE_TAG_MEM:
34362306a36Sopenharmony_ci			if (len != 9)
34462306a36Sopenharmony_ci				goto len_err;
34562306a36Sopenharmony_ci			pnpbios_parse_mem_option(dev, p, len, option_flags);
34662306a36Sopenharmony_ci			break;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		case LARGE_TAG_MEM32:
34962306a36Sopenharmony_ci			if (len != 17)
35062306a36Sopenharmony_ci				goto len_err;
35162306a36Sopenharmony_ci			pnpbios_parse_mem32_option(dev, p, len, option_flags);
35262306a36Sopenharmony_ci			break;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		case LARGE_TAG_FIXEDMEM32:
35562306a36Sopenharmony_ci			if (len != 9)
35662306a36Sopenharmony_ci				goto len_err;
35762306a36Sopenharmony_ci			pnpbios_parse_fixed_mem32_option(dev, p, len,
35862306a36Sopenharmony_ci							 option_flags);
35962306a36Sopenharmony_ci			break;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		case SMALL_TAG_IRQ:
36262306a36Sopenharmony_ci			if (len < 2 || len > 3)
36362306a36Sopenharmony_ci				goto len_err;
36462306a36Sopenharmony_ci			pnpbios_parse_irq_option(dev, p, len, option_flags);
36562306a36Sopenharmony_ci			break;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		case SMALL_TAG_DMA:
36862306a36Sopenharmony_ci			if (len != 2)
36962306a36Sopenharmony_ci				goto len_err;
37062306a36Sopenharmony_ci			pnpbios_parse_dma_option(dev, p, len, option_flags);
37162306a36Sopenharmony_ci			break;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		case SMALL_TAG_PORT:
37462306a36Sopenharmony_ci			if (len != 7)
37562306a36Sopenharmony_ci				goto len_err;
37662306a36Sopenharmony_ci			pnpbios_parse_port_option(dev, p, len, option_flags);
37762306a36Sopenharmony_ci			break;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		case SMALL_TAG_VENDOR:
38062306a36Sopenharmony_ci			/* do nothing */
38162306a36Sopenharmony_ci			break;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		case SMALL_TAG_FIXEDPORT:
38462306a36Sopenharmony_ci			if (len != 3)
38562306a36Sopenharmony_ci				goto len_err;
38662306a36Sopenharmony_ci			pnpbios_parse_fixed_port_option(dev, p, len,
38762306a36Sopenharmony_ci							option_flags);
38862306a36Sopenharmony_ci			break;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		case SMALL_TAG_STARTDEP:
39162306a36Sopenharmony_ci			if (len > 1)
39262306a36Sopenharmony_ci				goto len_err;
39362306a36Sopenharmony_ci			priority = PNP_RES_PRIORITY_ACCEPTABLE;
39462306a36Sopenharmony_ci			if (len > 0)
39562306a36Sopenharmony_ci				priority = p[1];
39662306a36Sopenharmony_ci			option_flags = pnp_new_dependent_set(dev, priority);
39762306a36Sopenharmony_ci			break;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci		case SMALL_TAG_ENDDEP:
40062306a36Sopenharmony_ci			if (len != 0)
40162306a36Sopenharmony_ci				goto len_err;
40262306a36Sopenharmony_ci			option_flags = 0;
40362306a36Sopenharmony_ci			break;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		case SMALL_TAG_END:
40662306a36Sopenharmony_ci			return p + 2;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		default:	/* an unknown tag */
40962306a36Sopenharmony_cilen_err:
41062306a36Sopenharmony_ci			dev_err(&dev->dev, "unknown tag %#x length %d\n",
41162306a36Sopenharmony_ci				tag, len);
41262306a36Sopenharmony_ci			break;
41362306a36Sopenharmony_ci		}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		/* continue to the next tag */
41662306a36Sopenharmony_ci		if (p[0] & LARGE_TAG)
41762306a36Sopenharmony_ci			p += len + 3;
41862306a36Sopenharmony_ci		else
41962306a36Sopenharmony_ci			p += len + 1;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	dev_err(&dev->dev, "no end tag in resource structure\n");
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return NULL;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci * Compatible Device IDs
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
43262306a36Sopenharmony_ci						   unsigned char *end,
43362306a36Sopenharmony_ci						   struct pnp_dev *dev)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	int len, tag;
43662306a36Sopenharmony_ci	u32 eisa_id;
43762306a36Sopenharmony_ci	char id[8];
43862306a36Sopenharmony_ci	struct pnp_id *dev_id;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (!p)
44162306a36Sopenharmony_ci		return NULL;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	while ((char *)p < (char *)end) {
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		/* determine the type of tag */
44662306a36Sopenharmony_ci		if (p[0] & LARGE_TAG) {	/* large tag */
44762306a36Sopenharmony_ci			len = (p[2] << 8) | p[1];
44862306a36Sopenharmony_ci			tag = p[0];
44962306a36Sopenharmony_ci		} else {	/* small tag */
45062306a36Sopenharmony_ci			len = p[0] & 0x07;
45162306a36Sopenharmony_ci			tag = ((p[0] >> 3) & 0x0f);
45262306a36Sopenharmony_ci		}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		switch (tag) {
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		case LARGE_TAG_ANSISTR:
45762306a36Sopenharmony_ci			strncpy(dev->name, p + 3,
45862306a36Sopenharmony_ci				len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
45962306a36Sopenharmony_ci			dev->name[len >=
46062306a36Sopenharmony_ci				  PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
46162306a36Sopenharmony_ci			break;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		case SMALL_TAG_COMPATDEVID:	/* compatible ID */
46462306a36Sopenharmony_ci			if (len != 4)
46562306a36Sopenharmony_ci				goto len_err;
46662306a36Sopenharmony_ci			eisa_id = p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24;
46762306a36Sopenharmony_ci			pnp_eisa_id_to_string(eisa_id & PNP_EISA_ID_MASK, id);
46862306a36Sopenharmony_ci			dev_id = pnp_add_id(dev, id);
46962306a36Sopenharmony_ci			if (!dev_id)
47062306a36Sopenharmony_ci				return NULL;
47162306a36Sopenharmony_ci			break;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		case SMALL_TAG_END:
47462306a36Sopenharmony_ci			p = p + 2;
47562306a36Sopenharmony_ci			return (unsigned char *)p;
47662306a36Sopenharmony_ci			break;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		default:	/* an unknown tag */
47962306a36Sopenharmony_cilen_err:
48062306a36Sopenharmony_ci			dev_err(&dev->dev, "unknown tag %#x length %d\n",
48162306a36Sopenharmony_ci				tag, len);
48262306a36Sopenharmony_ci			break;
48362306a36Sopenharmony_ci		}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		/* continue to the next tag */
48662306a36Sopenharmony_ci		if (p[0] & LARGE_TAG)
48762306a36Sopenharmony_ci			p += len + 3;
48862306a36Sopenharmony_ci		else
48962306a36Sopenharmony_ci			p += len + 1;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	dev_err(&dev->dev, "no end tag in resource structure\n");
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return NULL;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/*
49862306a36Sopenharmony_ci * Allocated Resource Encoding
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p,
50262306a36Sopenharmony_ci			       struct resource *res)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	unsigned long base;
50562306a36Sopenharmony_ci	unsigned long len;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (pnp_resource_enabled(res)) {
50862306a36Sopenharmony_ci		base = res->start;
50962306a36Sopenharmony_ci		len = resource_size(res);
51062306a36Sopenharmony_ci	} else {
51162306a36Sopenharmony_ci		base = 0;
51262306a36Sopenharmony_ci		len = 0;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	p[4] = (base >> 8) & 0xff;
51662306a36Sopenharmony_ci	p[5] = ((base >> 8) >> 8) & 0xff;
51762306a36Sopenharmony_ci	p[6] = (base >> 8) & 0xff;
51862306a36Sopenharmony_ci	p[7] = ((base >> 8) >> 8) & 0xff;
51962306a36Sopenharmony_ci	p[10] = (len >> 8) & 0xff;
52062306a36Sopenharmony_ci	p[11] = ((len >> 8) >> 8) & 0xff;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "  encode mem %#lx-%#lx\n", base, base + len - 1);
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p,
52662306a36Sopenharmony_ci				 struct resource *res)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	unsigned long base;
52962306a36Sopenharmony_ci	unsigned long len;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (pnp_resource_enabled(res)) {
53262306a36Sopenharmony_ci		base = res->start;
53362306a36Sopenharmony_ci		len = resource_size(res);
53462306a36Sopenharmony_ci	} else {
53562306a36Sopenharmony_ci		base = 0;
53662306a36Sopenharmony_ci		len = 0;
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	p[4] = base & 0xff;
54062306a36Sopenharmony_ci	p[5] = (base >> 8) & 0xff;
54162306a36Sopenharmony_ci	p[6] = (base >> 16) & 0xff;
54262306a36Sopenharmony_ci	p[7] = (base >> 24) & 0xff;
54362306a36Sopenharmony_ci	p[8] = base & 0xff;
54462306a36Sopenharmony_ci	p[9] = (base >> 8) & 0xff;
54562306a36Sopenharmony_ci	p[10] = (base >> 16) & 0xff;
54662306a36Sopenharmony_ci	p[11] = (base >> 24) & 0xff;
54762306a36Sopenharmony_ci	p[16] = len & 0xff;
54862306a36Sopenharmony_ci	p[17] = (len >> 8) & 0xff;
54962306a36Sopenharmony_ci	p[18] = (len >> 16) & 0xff;
55062306a36Sopenharmony_ci	p[19] = (len >> 24) & 0xff;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "  encode mem32 %#lx-%#lx\n", base, base + len - 1);
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p,
55662306a36Sopenharmony_ci				       struct resource *res)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	unsigned long base;
55962306a36Sopenharmony_ci	unsigned long len;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (pnp_resource_enabled(res)) {
56262306a36Sopenharmony_ci		base = res->start;
56362306a36Sopenharmony_ci		len = resource_size(res);
56462306a36Sopenharmony_ci	} else {
56562306a36Sopenharmony_ci		base = 0;
56662306a36Sopenharmony_ci		len = 0;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	p[4] = base & 0xff;
57062306a36Sopenharmony_ci	p[5] = (base >> 8) & 0xff;
57162306a36Sopenharmony_ci	p[6] = (base >> 16) & 0xff;
57262306a36Sopenharmony_ci	p[7] = (base >> 24) & 0xff;
57362306a36Sopenharmony_ci	p[8] = len & 0xff;
57462306a36Sopenharmony_ci	p[9] = (len >> 8) & 0xff;
57562306a36Sopenharmony_ci	p[10] = (len >> 16) & 0xff;
57662306a36Sopenharmony_ci	p[11] = (len >> 24) & 0xff;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "  encode fixed_mem32 %#lx-%#lx\n", base,
57962306a36Sopenharmony_ci		base + len - 1);
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p,
58362306a36Sopenharmony_ci			       struct resource *res)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	unsigned long map;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (pnp_resource_enabled(res))
58862306a36Sopenharmony_ci		map = 1 << res->start;
58962306a36Sopenharmony_ci	else
59062306a36Sopenharmony_ci		map = 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	p[1] = map & 0xff;
59362306a36Sopenharmony_ci	p[2] = (map >> 8) & 0xff;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "  encode irq mask %#lx\n", map);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
59962306a36Sopenharmony_ci			       struct resource *res)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	unsigned long map;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (pnp_resource_enabled(res))
60462306a36Sopenharmony_ci		map = 1 << res->start;
60562306a36Sopenharmony_ci	else
60662306a36Sopenharmony_ci		map = 0;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	p[1] = map & 0xff;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "  encode dma mask %#lx\n", map);
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
61462306a36Sopenharmony_ci				struct resource *res)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	unsigned long base;
61762306a36Sopenharmony_ci	unsigned long len;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (pnp_resource_enabled(res)) {
62062306a36Sopenharmony_ci		base = res->start;
62162306a36Sopenharmony_ci		len = resource_size(res);
62262306a36Sopenharmony_ci	} else {
62362306a36Sopenharmony_ci		base = 0;
62462306a36Sopenharmony_ci		len = 0;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	p[2] = base & 0xff;
62862306a36Sopenharmony_ci	p[3] = (base >> 8) & 0xff;
62962306a36Sopenharmony_ci	p[4] = base & 0xff;
63062306a36Sopenharmony_ci	p[5] = (base >> 8) & 0xff;
63162306a36Sopenharmony_ci	p[7] = len & 0xff;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "  encode io %#lx-%#lx\n", base, base + len - 1);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p,
63762306a36Sopenharmony_ci				      struct resource *res)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	unsigned long base = res->start;
64062306a36Sopenharmony_ci	unsigned long len = resource_size(res);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (pnp_resource_enabled(res)) {
64362306a36Sopenharmony_ci		base = res->start;
64462306a36Sopenharmony_ci		len = resource_size(res);
64562306a36Sopenharmony_ci	} else {
64662306a36Sopenharmony_ci		base = 0;
64762306a36Sopenharmony_ci		len = 0;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	p[1] = base & 0xff;
65162306a36Sopenharmony_ci	p[2] = (base >> 8) & 0xff;
65262306a36Sopenharmony_ci	p[3] = len & 0xff;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	pnp_dbg(&dev->dev, "  encode fixed_io %#lx-%#lx\n", base,
65562306a36Sopenharmony_ci		base + len - 1);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev
65962306a36Sopenharmony_ci								*dev,
66062306a36Sopenharmony_ci							     unsigned char *p,
66162306a36Sopenharmony_ci							     unsigned char *end)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	unsigned int len, tag;
66462306a36Sopenharmony_ci	int port = 0, irq = 0, dma = 0, mem = 0;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (!p)
66762306a36Sopenharmony_ci		return NULL;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	while ((char *)p < (char *)end) {
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		/* determine the type of tag */
67262306a36Sopenharmony_ci		if (p[0] & LARGE_TAG) {	/* large tag */
67362306a36Sopenharmony_ci			len = (p[2] << 8) | p[1];
67462306a36Sopenharmony_ci			tag = p[0];
67562306a36Sopenharmony_ci		} else {	/* small tag */
67662306a36Sopenharmony_ci			len = p[0] & 0x07;
67762306a36Sopenharmony_ci			tag = ((p[0] >> 3) & 0x0f);
67862306a36Sopenharmony_ci		}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		switch (tag) {
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		case LARGE_TAG_MEM:
68362306a36Sopenharmony_ci			if (len != 9)
68462306a36Sopenharmony_ci				goto len_err;
68562306a36Sopenharmony_ci			pnpbios_encode_mem(dev, p,
68662306a36Sopenharmony_ci				pnp_get_resource(dev, IORESOURCE_MEM, mem));
68762306a36Sopenharmony_ci			mem++;
68862306a36Sopenharmony_ci			break;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci		case LARGE_TAG_MEM32:
69162306a36Sopenharmony_ci			if (len != 17)
69262306a36Sopenharmony_ci				goto len_err;
69362306a36Sopenharmony_ci			pnpbios_encode_mem32(dev, p,
69462306a36Sopenharmony_ci				pnp_get_resource(dev, IORESOURCE_MEM, mem));
69562306a36Sopenharmony_ci			mem++;
69662306a36Sopenharmony_ci			break;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		case LARGE_TAG_FIXEDMEM32:
69962306a36Sopenharmony_ci			if (len != 9)
70062306a36Sopenharmony_ci				goto len_err;
70162306a36Sopenharmony_ci			pnpbios_encode_fixed_mem32(dev, p,
70262306a36Sopenharmony_ci				pnp_get_resource(dev, IORESOURCE_MEM, mem));
70362306a36Sopenharmony_ci			mem++;
70462306a36Sopenharmony_ci			break;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		case SMALL_TAG_IRQ:
70762306a36Sopenharmony_ci			if (len < 2 || len > 3)
70862306a36Sopenharmony_ci				goto len_err;
70962306a36Sopenharmony_ci			pnpbios_encode_irq(dev, p,
71062306a36Sopenharmony_ci				pnp_get_resource(dev, IORESOURCE_IRQ, irq));
71162306a36Sopenharmony_ci			irq++;
71262306a36Sopenharmony_ci			break;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		case SMALL_TAG_DMA:
71562306a36Sopenharmony_ci			if (len != 2)
71662306a36Sopenharmony_ci				goto len_err;
71762306a36Sopenharmony_ci			pnpbios_encode_dma(dev, p,
71862306a36Sopenharmony_ci				pnp_get_resource(dev, IORESOURCE_DMA, dma));
71962306a36Sopenharmony_ci			dma++;
72062306a36Sopenharmony_ci			break;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci		case SMALL_TAG_PORT:
72362306a36Sopenharmony_ci			if (len != 7)
72462306a36Sopenharmony_ci				goto len_err;
72562306a36Sopenharmony_ci			pnpbios_encode_port(dev, p,
72662306a36Sopenharmony_ci				pnp_get_resource(dev, IORESOURCE_IO, port));
72762306a36Sopenharmony_ci			port++;
72862306a36Sopenharmony_ci			break;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		case SMALL_TAG_VENDOR:
73162306a36Sopenharmony_ci			/* do nothing */
73262306a36Sopenharmony_ci			break;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci		case SMALL_TAG_FIXEDPORT:
73562306a36Sopenharmony_ci			if (len != 3)
73662306a36Sopenharmony_ci				goto len_err;
73762306a36Sopenharmony_ci			pnpbios_encode_fixed_port(dev, p,
73862306a36Sopenharmony_ci				pnp_get_resource(dev, IORESOURCE_IO, port));
73962306a36Sopenharmony_ci			port++;
74062306a36Sopenharmony_ci			break;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		case SMALL_TAG_END:
74362306a36Sopenharmony_ci			p = p + 2;
74462306a36Sopenharmony_ci			return (unsigned char *)p;
74562306a36Sopenharmony_ci			break;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		default:	/* an unknown tag */
74862306a36Sopenharmony_cilen_err:
74962306a36Sopenharmony_ci			dev_err(&dev->dev, "unknown tag %#x length %d\n",
75062306a36Sopenharmony_ci				tag, len);
75162306a36Sopenharmony_ci			break;
75262306a36Sopenharmony_ci		}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		/* continue to the next tag */
75562306a36Sopenharmony_ci		if (p[0] & LARGE_TAG)
75662306a36Sopenharmony_ci			p += len + 3;
75762306a36Sopenharmony_ci		else
75862306a36Sopenharmony_ci			p += len + 1;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	dev_err(&dev->dev, "no end tag in resource structure\n");
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	return NULL;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci/*
76762306a36Sopenharmony_ci * Core Parsing Functions
76862306a36Sopenharmony_ci */
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ciint __init pnpbios_parse_data_stream(struct pnp_dev *dev,
77162306a36Sopenharmony_ci					struct pnp_bios_node *node)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	unsigned char *p = (char *)node->data;
77462306a36Sopenharmony_ci	unsigned char *end = (char *)(node->data + node->size);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	p = pnpbios_parse_allocated_resource_data(dev, p, end);
77762306a36Sopenharmony_ci	if (!p)
77862306a36Sopenharmony_ci		return -EIO;
77962306a36Sopenharmony_ci	p = pnpbios_parse_resource_option_data(p, end, dev);
78062306a36Sopenharmony_ci	if (!p)
78162306a36Sopenharmony_ci		return -EIO;
78262306a36Sopenharmony_ci	p = pnpbios_parse_compatible_ids(p, end, dev);
78362306a36Sopenharmony_ci	if (!p)
78462306a36Sopenharmony_ci		return -EIO;
78562306a36Sopenharmony_ci	return 0;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ciint pnpbios_read_resources_from_node(struct pnp_dev *dev,
78962306a36Sopenharmony_ci				     struct pnp_bios_node *node)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	unsigned char *p = (char *)node->data;
79262306a36Sopenharmony_ci	unsigned char *end = (char *)(node->data + node->size);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	p = pnpbios_parse_allocated_resource_data(dev, p, end);
79562306a36Sopenharmony_ci	if (!p)
79662306a36Sopenharmony_ci		return -EIO;
79762306a36Sopenharmony_ci	return 0;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ciint pnpbios_write_resources_to_node(struct pnp_dev *dev,
80162306a36Sopenharmony_ci				    struct pnp_bios_node *node)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	unsigned char *p = (char *)node->data;
80462306a36Sopenharmony_ci	unsigned char *end = (char *)(node->data + node->size);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	p = pnpbios_encode_allocated_resource_data(dev, p, end);
80762306a36Sopenharmony_ci	if (!p)
80862306a36Sopenharmony_ci		return -EIO;
80962306a36Sopenharmony_ci	return 0;
81062306a36Sopenharmony_ci}
811