xref: /linux/drivers/pnp/pnpbios/rsparser.c (revision a23e1966932464e1c5226cb9ac4ce1d5fc10ba22)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * rsparser.c - parses and encodes pnpbios resource data streams
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <linux/ctype.h>
71da177e4SLinus Torvalds #include <linux/pnp.h>
84e57b681STim Schmielau #include <linux/string.h>
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #ifdef CONFIG_PCI
111da177e4SLinus Torvalds #include <linux/pci.h>
121da177e4SLinus Torvalds #else
pcibios_penalize_isa_irq(int irq,int active)139dd78466SBjorn Helgaas inline void pcibios_penalize_isa_irq(int irq, int active)
149dd78466SBjorn Helgaas {
159dd78466SBjorn Helgaas }
161da177e4SLinus Torvalds #endif				/* CONFIG_PCI */
171da177e4SLinus Torvalds 
18772defc6SBjorn Helgaas #include "../base.h"
191da177e4SLinus Torvalds #include "pnpbios.h"
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds /* standard resource tags */
221da177e4SLinus Torvalds #define SMALL_TAG_PNPVERNO		0x01
231da177e4SLinus Torvalds #define SMALL_TAG_LOGDEVID		0x02
241da177e4SLinus Torvalds #define SMALL_TAG_COMPATDEVID		0x03
251da177e4SLinus Torvalds #define SMALL_TAG_IRQ			0x04
261da177e4SLinus Torvalds #define SMALL_TAG_DMA			0x05
271da177e4SLinus Torvalds #define SMALL_TAG_STARTDEP		0x06
281da177e4SLinus Torvalds #define SMALL_TAG_ENDDEP		0x07
291da177e4SLinus Torvalds #define SMALL_TAG_PORT			0x08
301da177e4SLinus Torvalds #define SMALL_TAG_FIXEDPORT		0x09
311da177e4SLinus Torvalds #define SMALL_TAG_VENDOR		0x0e
321da177e4SLinus Torvalds #define SMALL_TAG_END			0x0f
331da177e4SLinus Torvalds #define LARGE_TAG			0x80
341da177e4SLinus Torvalds #define LARGE_TAG_MEM			0x81
351da177e4SLinus Torvalds #define LARGE_TAG_ANSISTR		0x82
361da177e4SLinus Torvalds #define LARGE_TAG_UNICODESTR		0x83
371da177e4SLinus Torvalds #define LARGE_TAG_VENDOR		0x84
381da177e4SLinus Torvalds #define LARGE_TAG_MEM32			0x85
391da177e4SLinus Torvalds #define LARGE_TAG_FIXEDMEM32		0x86
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds /*
421da177e4SLinus Torvalds  * Resource Data Stream Format:
431da177e4SLinus Torvalds  *
441da177e4SLinus Torvalds  * Allocated Resources (required)
451da177e4SLinus Torvalds  * end tag ->
461da177e4SLinus Torvalds  * Resource Configuration Options (optional)
471da177e4SLinus Torvalds  * end tag ->
481da177e4SLinus Torvalds  * Compitable Device IDs (optional)
491da177e4SLinus Torvalds  * final end tag ->
501da177e4SLinus Torvalds  */
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds /*
531da177e4SLinus Torvalds  * Allocated Resources
541da177e4SLinus Torvalds  */
551da177e4SLinus Torvalds 
pnpbios_parse_allocated_ioresource(struct pnp_dev * dev,int start,int len)564ab55d8dSBjorn Helgaas static void pnpbios_parse_allocated_ioresource(struct pnp_dev *dev,
57cc8c2e30SBjorn Helgaas 					       int start, int len)
581da177e4SLinus Torvalds {
59cc8c2e30SBjorn Helgaas 	int flags = 0;
60cc8c2e30SBjorn Helgaas 	int end = start + len - 1;
6107d4e9afSBjorn Helgaas 
62cc8c2e30SBjorn Helgaas 	if (len <= 0 || end >= 0x10003)
63cc8c2e30SBjorn Helgaas 		flags |= IORESOURCE_DISABLED;
6406cb58a6SBjorn Helgaas 
65cc8c2e30SBjorn Helgaas 	pnp_add_io_resource(dev, start, end, flags);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
pnpbios_parse_allocated_memresource(struct pnp_dev * dev,int start,int len)684ab55d8dSBjorn Helgaas static void pnpbios_parse_allocated_memresource(struct pnp_dev *dev,
69d6180f36SBjorn Helgaas 						int start, int len)
701da177e4SLinus Torvalds {
71d6180f36SBjorn Helgaas 	int flags = 0;
72d6180f36SBjorn Helgaas 	int end = start + len - 1;
7307d4e9afSBjorn Helgaas 
74d6180f36SBjorn Helgaas 	if (len <= 0)
75d6180f36SBjorn Helgaas 		flags |= IORESOURCE_DISABLED;
7606cb58a6SBjorn Helgaas 
77d6180f36SBjorn Helgaas 	pnp_add_mem_resource(dev, start, end, flags);
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds 
pnpbios_parse_allocated_resource_data(struct pnp_dev * dev,unsigned char * p,unsigned char * end)804ab55d8dSBjorn Helgaas static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev,
814ab55d8dSBjorn Helgaas 							    unsigned char *p,
824ab55d8dSBjorn Helgaas 							    unsigned char *end)
831da177e4SLinus Torvalds {
841da177e4SLinus Torvalds 	unsigned int len, tag;
85dbddd038SBjorn Helgaas 	int io, size, mask, i, flags;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 	if (!p)
881da177e4SLinus Torvalds 		return NULL;
891da177e4SLinus Torvalds 
902f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "parse allocated resources\n");
9172dcc883SBjorn Helgaas 
92f4490002SBjorn Helgaas 	pnp_init_resources(dev);
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	while ((char *)p < (char *)end) {
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 		/* determine the type of tag */
971da177e4SLinus Torvalds 		if (p[0] & LARGE_TAG) {	/* large tag */
981da177e4SLinus Torvalds 			len = (p[2] << 8) | p[1];
991da177e4SLinus Torvalds 			tag = p[0];
1001da177e4SLinus Torvalds 		} else {	/* small tag */
1011da177e4SLinus Torvalds 			len = p[0] & 0x07;
1021da177e4SLinus Torvalds 			tag = ((p[0] >> 3) & 0x0f);
1031da177e4SLinus Torvalds 		}
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 		switch (tag) {
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 		case LARGE_TAG_MEM:
1081da177e4SLinus Torvalds 			if (len != 9)
1091da177e4SLinus Torvalds 				goto len_err;
1101da177e4SLinus Torvalds 			io = *(short *)&p[4];
1111da177e4SLinus Torvalds 			size = *(short *)&p[10];
1124ab55d8dSBjorn Helgaas 			pnpbios_parse_allocated_memresource(dev, io, size);
1131da177e4SLinus Torvalds 			break;
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds 		case LARGE_TAG_ANSISTR:
1161da177e4SLinus Torvalds 			/* ignore this for now */
1171da177e4SLinus Torvalds 			break;
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 		case LARGE_TAG_VENDOR:
1201da177e4SLinus Torvalds 			/* do nothing */
1211da177e4SLinus Torvalds 			break;
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 		case LARGE_TAG_MEM32:
1241da177e4SLinus Torvalds 			if (len != 17)
1251da177e4SLinus Torvalds 				goto len_err;
1261da177e4SLinus Torvalds 			io = *(int *)&p[4];
1271da177e4SLinus Torvalds 			size = *(int *)&p[16];
1284ab55d8dSBjorn Helgaas 			pnpbios_parse_allocated_memresource(dev, io, size);
1291da177e4SLinus Torvalds 			break;
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 		case LARGE_TAG_FIXEDMEM32:
1321da177e4SLinus Torvalds 			if (len != 9)
1331da177e4SLinus Torvalds 				goto len_err;
1341da177e4SLinus Torvalds 			io = *(int *)&p[4];
1351da177e4SLinus Torvalds 			size = *(int *)&p[8];
1364ab55d8dSBjorn Helgaas 			pnpbios_parse_allocated_memresource(dev, io, size);
1371da177e4SLinus Torvalds 			break;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 		case SMALL_TAG_IRQ:
1401da177e4SLinus Torvalds 			if (len < 2 || len > 3)
1411da177e4SLinus Torvalds 				goto len_err;
142dbddd038SBjorn Helgaas 			flags = 0;
1431da177e4SLinus Torvalds 			io = -1;
1441da177e4SLinus Torvalds 			mask = p[1] + p[2] * 256;
1451da177e4SLinus Torvalds 			for (i = 0; i < 16; i++, mask = mask >> 1)
1469dd78466SBjorn Helgaas 				if (mask & 0x01)
1479dd78466SBjorn Helgaas 					io = i;
148dbddd038SBjorn Helgaas 			if (io != -1)
149dbddd038SBjorn Helgaas 				pcibios_penalize_isa_irq(io, 1);
150dbddd038SBjorn Helgaas 			else
151dbddd038SBjorn Helgaas 				flags = IORESOURCE_DISABLED;
152dbddd038SBjorn Helgaas 			pnp_add_irq_resource(dev, io, flags);
1531da177e4SLinus Torvalds 			break;
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 		case SMALL_TAG_DMA:
1561da177e4SLinus Torvalds 			if (len != 2)
1571da177e4SLinus Torvalds 				goto len_err;
158dc16f5f2SBjorn Helgaas 			flags = 0;
1591da177e4SLinus Torvalds 			io = -1;
1601da177e4SLinus Torvalds 			mask = p[1];
1611da177e4SLinus Torvalds 			for (i = 0; i < 8; i++, mask = mask >> 1)
1629dd78466SBjorn Helgaas 				if (mask & 0x01)
1639dd78466SBjorn Helgaas 					io = i;
164dc16f5f2SBjorn Helgaas 			if (io == -1)
165dc16f5f2SBjorn Helgaas 				flags = IORESOURCE_DISABLED;
166dc16f5f2SBjorn Helgaas 			pnp_add_dma_resource(dev, io, flags);
1671da177e4SLinus Torvalds 			break;
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds 		case SMALL_TAG_PORT:
1701da177e4SLinus Torvalds 			if (len != 7)
1711da177e4SLinus Torvalds 				goto len_err;
1721da177e4SLinus Torvalds 			io = p[2] + p[3] * 256;
1731da177e4SLinus Torvalds 			size = p[7];
1744ab55d8dSBjorn Helgaas 			pnpbios_parse_allocated_ioresource(dev, io, size);
1751da177e4SLinus Torvalds 			break;
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 		case SMALL_TAG_VENDOR:
1781da177e4SLinus Torvalds 			/* do nothing */
1791da177e4SLinus Torvalds 			break;
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 		case SMALL_TAG_FIXEDPORT:
1821da177e4SLinus Torvalds 			if (len != 3)
1831da177e4SLinus Torvalds 				goto len_err;
1841da177e4SLinus Torvalds 			io = p[1] + p[2] * 256;
1851da177e4SLinus Torvalds 			size = p[3];
1864ab55d8dSBjorn Helgaas 			pnpbios_parse_allocated_ioresource(dev, io, size);
1871da177e4SLinus Torvalds 			break;
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 		case SMALL_TAG_END:
1901da177e4SLinus Torvalds 			p = p + 2;
1911da177e4SLinus Torvalds 			return (unsigned char *)p;
1921da177e4SLinus Torvalds 			break;
1931da177e4SLinus Torvalds 
194af901ca1SAndré Goddard Rosa 		default:	/* an unknown tag */
1951da177e4SLinus Torvalds len_err:
196af11cb2dSBjorn Helgaas 			dev_err(&dev->dev, "unknown tag %#x length %d\n",
1979dd78466SBjorn Helgaas 				tag, len);
1981da177e4SLinus Torvalds 			break;
1991da177e4SLinus Torvalds 		}
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 		/* continue to the next tag */
2021da177e4SLinus Torvalds 		if (p[0] & LARGE_TAG)
2031da177e4SLinus Torvalds 			p += len + 3;
2041da177e4SLinus Torvalds 		else
2051da177e4SLinus Torvalds 			p += len + 1;
2061da177e4SLinus Torvalds 	}
2071da177e4SLinus Torvalds 
208af11cb2dSBjorn Helgaas 	dev_err(&dev->dev, "no end tag in resource structure\n");
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 	return NULL;
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds /*
2141da177e4SLinus Torvalds  * Resource Configuration Options
2151da177e4SLinus Torvalds  */
2161da177e4SLinus Torvalds 
pnpbios_parse_mem_option(struct pnp_dev * dev,unsigned char * p,int size,unsigned int option_flags)217c1caf06cSBjorn Helgaas static __init void pnpbios_parse_mem_option(struct pnp_dev *dev,
218c1caf06cSBjorn Helgaas 					    unsigned char *p, int size,
2191f32ca31SBjorn Helgaas 					    unsigned int option_flags)
2201da177e4SLinus Torvalds {
221c227536bSBjorn Helgaas 	resource_size_t min, max, align, len;
222c227536bSBjorn Helgaas 	unsigned char flags;
22307d4e9afSBjorn Helgaas 
224c227536bSBjorn Helgaas 	min = ((p[5] << 8) | p[4]) << 8;
225c227536bSBjorn Helgaas 	max = ((p[7] << 8) | p[6]) << 8;
226c227536bSBjorn Helgaas 	align = (p[9] << 8) | p[8];
227c227536bSBjorn Helgaas 	len = ((p[11] << 8) | p[10]) << 8;
228c227536bSBjorn Helgaas 	flags = p[3];
2291f32ca31SBjorn Helgaas 	pnp_register_mem_resource(dev, option_flags, min, max, align, len,
2301f32ca31SBjorn Helgaas 				  flags);
2311da177e4SLinus Torvalds }
2321da177e4SLinus Torvalds 
pnpbios_parse_mem32_option(struct pnp_dev * dev,unsigned char * p,int size,unsigned int option_flags)233c1caf06cSBjorn Helgaas static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev,
234c1caf06cSBjorn Helgaas 					      unsigned char *p, int size,
2351f32ca31SBjorn Helgaas 					      unsigned int option_flags)
2361da177e4SLinus Torvalds {
237c227536bSBjorn Helgaas 	resource_size_t min, max, align, len;
238c227536bSBjorn Helgaas 	unsigned char flags;
23907d4e9afSBjorn Helgaas 
240c227536bSBjorn Helgaas 	min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
241c227536bSBjorn Helgaas 	max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
242c227536bSBjorn Helgaas 	align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
243c227536bSBjorn Helgaas 	len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
244c227536bSBjorn Helgaas 	flags = p[3];
2451f32ca31SBjorn Helgaas 	pnp_register_mem_resource(dev, option_flags, min, max, align, len,
2461f32ca31SBjorn Helgaas 				  flags);
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
pnpbios_parse_fixed_mem32_option(struct pnp_dev * dev,unsigned char * p,int size,unsigned int option_flags)249c1caf06cSBjorn Helgaas static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev,
250c1caf06cSBjorn Helgaas 						    unsigned char *p, int size,
2511f32ca31SBjorn Helgaas 						    unsigned int option_flags)
2521da177e4SLinus Torvalds {
253c227536bSBjorn Helgaas 	resource_size_t base, len;
254c227536bSBjorn Helgaas 	unsigned char flags;
2551e0aa9adSBjorn Helgaas 
256c227536bSBjorn Helgaas 	base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
257c227536bSBjorn Helgaas 	len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
258c227536bSBjorn Helgaas 	flags = p[3];
2591f32ca31SBjorn Helgaas 	pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags);
2601da177e4SLinus Torvalds }
2611da177e4SLinus Torvalds 
pnpbios_parse_irq_option(struct pnp_dev * dev,unsigned char * p,int size,unsigned int option_flags)262c1caf06cSBjorn Helgaas static __init void pnpbios_parse_irq_option(struct pnp_dev *dev,
263c1caf06cSBjorn Helgaas 					    unsigned char *p, int size,
2641f32ca31SBjorn Helgaas 					    unsigned int option_flags)
2651da177e4SLinus Torvalds {
2661da177e4SLinus Torvalds 	unsigned long bits;
267c227536bSBjorn Helgaas 	pnp_irq_mask_t map;
268c227536bSBjorn Helgaas 	unsigned char flags = IORESOURCE_IRQ_HIGHEDGE;
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 	bits = (p[2] << 8) | p[1];
271c227536bSBjorn Helgaas 
272c227536bSBjorn Helgaas 	bitmap_zero(map.bits, PNP_IRQ_NR);
273c227536bSBjorn Helgaas 	bitmap_copy(map.bits, &bits, 16);
274c227536bSBjorn Helgaas 
2751da177e4SLinus Torvalds 	if (size > 2)
276c227536bSBjorn Helgaas 		flags = p[3];
277c227536bSBjorn Helgaas 
2781f32ca31SBjorn Helgaas 	pnp_register_irq_resource(dev, option_flags, &map, flags);
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds 
pnpbios_parse_dma_option(struct pnp_dev * dev,unsigned char * p,int size,unsigned int option_flags)281c1caf06cSBjorn Helgaas static __init void pnpbios_parse_dma_option(struct pnp_dev *dev,
282c1caf06cSBjorn Helgaas 					    unsigned char *p, int size,
2831f32ca31SBjorn Helgaas 					    unsigned int option_flags)
2841da177e4SLinus Torvalds {
2851f32ca31SBjorn Helgaas 	pnp_register_dma_resource(dev, option_flags, p[1], p[2]);
2861da177e4SLinus Torvalds }
2871da177e4SLinus Torvalds 
pnpbios_parse_port_option(struct pnp_dev * dev,unsigned char * p,int size,unsigned int option_flags)288c1caf06cSBjorn Helgaas static __init void pnpbios_parse_port_option(struct pnp_dev *dev,
289c1caf06cSBjorn Helgaas 					     unsigned char *p, int size,
2901f32ca31SBjorn Helgaas 					     unsigned int option_flags)
2911da177e4SLinus Torvalds {
292c227536bSBjorn Helgaas 	resource_size_t min, max, align, len;
293c227536bSBjorn Helgaas 	unsigned char flags;
29407d4e9afSBjorn Helgaas 
295c227536bSBjorn Helgaas 	min = (p[3] << 8) | p[2];
296c227536bSBjorn Helgaas 	max = (p[5] << 8) | p[4];
297c227536bSBjorn Helgaas 	align = p[6];
298c227536bSBjorn Helgaas 	len = p[7];
299c227536bSBjorn Helgaas 	flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0;
3001f32ca31SBjorn Helgaas 	pnp_register_port_resource(dev, option_flags, min, max, align, len,
3011f32ca31SBjorn Helgaas 				   flags);
3021da177e4SLinus Torvalds }
3031da177e4SLinus Torvalds 
pnpbios_parse_fixed_port_option(struct pnp_dev * dev,unsigned char * p,int size,unsigned int option_flags)304c1caf06cSBjorn Helgaas static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev,
305c1caf06cSBjorn Helgaas 						   unsigned char *p, int size,
3061f32ca31SBjorn Helgaas 						   unsigned int option_flags)
3071da177e4SLinus Torvalds {
308c227536bSBjorn Helgaas 	resource_size_t base, len;
30907d4e9afSBjorn Helgaas 
310c227536bSBjorn Helgaas 	base = (p[2] << 8) | p[1];
311c227536bSBjorn Helgaas 	len = p[3];
3121f32ca31SBjorn Helgaas 	pnp_register_port_resource(dev, option_flags, base, base, 0, len,
313c227536bSBjorn Helgaas 				   IORESOURCE_IO_FIXED);
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
3162bb9a6b3SThomas Renninger static __init unsigned char *
pnpbios_parse_resource_option_data(unsigned char * p,unsigned char * end,struct pnp_dev * dev)3172bb9a6b3SThomas Renninger pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
3189dd78466SBjorn Helgaas 				   struct pnp_dev *dev)
3191da177e4SLinus Torvalds {
3201da177e4SLinus Torvalds 	unsigned int len, tag;
321e2a1a6f1SBjorn Helgaas 	int priority;
3221f32ca31SBjorn Helgaas 	unsigned int option_flags;
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	if (!p)
3251da177e4SLinus Torvalds 		return NULL;
3261da177e4SLinus Torvalds 
3272f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "parse resource options\n");
3281f32ca31SBjorn Helgaas 	option_flags = 0;
3291da177e4SLinus Torvalds 	while ((char *)p < (char *)end) {
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 		/* determine the type of tag */
3321da177e4SLinus Torvalds 		if (p[0] & LARGE_TAG) {	/* large tag */
3331da177e4SLinus Torvalds 			len = (p[2] << 8) | p[1];
3341da177e4SLinus Torvalds 			tag = p[0];
3351da177e4SLinus Torvalds 		} else {	/* small tag */
3361da177e4SLinus Torvalds 			len = p[0] & 0x07;
3371da177e4SLinus Torvalds 			tag = ((p[0] >> 3) & 0x0f);
3381da177e4SLinus Torvalds 		}
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 		switch (tag) {
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 		case LARGE_TAG_MEM:
3431da177e4SLinus Torvalds 			if (len != 9)
3441da177e4SLinus Torvalds 				goto len_err;
3451f32ca31SBjorn Helgaas 			pnpbios_parse_mem_option(dev, p, len, option_flags);
3461da177e4SLinus Torvalds 			break;
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 		case LARGE_TAG_MEM32:
3491da177e4SLinus Torvalds 			if (len != 17)
3501da177e4SLinus Torvalds 				goto len_err;
3511f32ca31SBjorn Helgaas 			pnpbios_parse_mem32_option(dev, p, len, option_flags);
3521da177e4SLinus Torvalds 			break;
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 		case LARGE_TAG_FIXEDMEM32:
3551da177e4SLinus Torvalds 			if (len != 9)
3561da177e4SLinus Torvalds 				goto len_err;
3571f32ca31SBjorn Helgaas 			pnpbios_parse_fixed_mem32_option(dev, p, len,
3581f32ca31SBjorn Helgaas 							 option_flags);
3591da177e4SLinus Torvalds 			break;
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 		case SMALL_TAG_IRQ:
3621da177e4SLinus Torvalds 			if (len < 2 || len > 3)
3631da177e4SLinus Torvalds 				goto len_err;
3641f32ca31SBjorn Helgaas 			pnpbios_parse_irq_option(dev, p, len, option_flags);
3651da177e4SLinus Torvalds 			break;
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds 		case SMALL_TAG_DMA:
3681da177e4SLinus Torvalds 			if (len != 2)
3691da177e4SLinus Torvalds 				goto len_err;
3701f32ca31SBjorn Helgaas 			pnpbios_parse_dma_option(dev, p, len, option_flags);
3711da177e4SLinus Torvalds 			break;
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 		case SMALL_TAG_PORT:
3741da177e4SLinus Torvalds 			if (len != 7)
3751da177e4SLinus Torvalds 				goto len_err;
3761f32ca31SBjorn Helgaas 			pnpbios_parse_port_option(dev, p, len, option_flags);
3771da177e4SLinus Torvalds 			break;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 		case SMALL_TAG_VENDOR:
3801da177e4SLinus Torvalds 			/* do nothing */
3811da177e4SLinus Torvalds 			break;
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 		case SMALL_TAG_FIXEDPORT:
3841da177e4SLinus Torvalds 			if (len != 3)
3851da177e4SLinus Torvalds 				goto len_err;
3861f32ca31SBjorn Helgaas 			pnpbios_parse_fixed_port_option(dev, p, len,
3871f32ca31SBjorn Helgaas 							option_flags);
3881da177e4SLinus Torvalds 			break;
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds 		case SMALL_TAG_STARTDEP:
3911da177e4SLinus Torvalds 			if (len > 1)
3921da177e4SLinus Torvalds 				goto len_err;
393e2a1a6f1SBjorn Helgaas 			priority = PNP_RES_PRIORITY_ACCEPTABLE;
3941da177e4SLinus Torvalds 			if (len > 0)
395e2a1a6f1SBjorn Helgaas 				priority = p[1];
3961f32ca31SBjorn Helgaas 			option_flags = pnp_new_dependent_set(dev, priority);
3971da177e4SLinus Torvalds 			break;
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 		case SMALL_TAG_ENDDEP:
4001da177e4SLinus Torvalds 			if (len != 0)
4011da177e4SLinus Torvalds 				goto len_err;
4021f32ca31SBjorn Helgaas 			option_flags = 0;
4031da177e4SLinus Torvalds 			break;
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds 		case SMALL_TAG_END:
406eb8782efSRene Herman 			return p + 2;
4071da177e4SLinus Torvalds 
408af901ca1SAndré Goddard Rosa 		default:	/* an unknown tag */
4091da177e4SLinus Torvalds len_err:
410af11cb2dSBjorn Helgaas 			dev_err(&dev->dev, "unknown tag %#x length %d\n",
4119dd78466SBjorn Helgaas 				tag, len);
4121da177e4SLinus Torvalds 			break;
4131da177e4SLinus Torvalds 		}
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 		/* continue to the next tag */
4161da177e4SLinus Torvalds 		if (p[0] & LARGE_TAG)
4171da177e4SLinus Torvalds 			p += len + 3;
4181da177e4SLinus Torvalds 		else
4191da177e4SLinus Torvalds 			p += len + 1;
4201da177e4SLinus Torvalds 	}
4211da177e4SLinus Torvalds 
422af11cb2dSBjorn Helgaas 	dev_err(&dev->dev, "no end tag in resource structure\n");
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 	return NULL;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds /*
4281da177e4SLinus Torvalds  * Compatible Device IDs
4291da177e4SLinus Torvalds  */
4301da177e4SLinus Torvalds 
pnpbios_parse_compatible_ids(unsigned char * p,unsigned char * end,struct pnp_dev * dev)4319dd78466SBjorn Helgaas static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
4329dd78466SBjorn Helgaas 						   unsigned char *end,
4339dd78466SBjorn Helgaas 						   struct pnp_dev *dev)
4341da177e4SLinus Torvalds {
4351da177e4SLinus Torvalds 	int len, tag;
43625eb8461SBjorn Helgaas 	u32 eisa_id;
4371da177e4SLinus Torvalds 	char id[8];
4381da177e4SLinus Torvalds 	struct pnp_id *dev_id;
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds 	if (!p)
4411da177e4SLinus Torvalds 		return NULL;
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 	while ((char *)p < (char *)end) {
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 		/* determine the type of tag */
4461da177e4SLinus Torvalds 		if (p[0] & LARGE_TAG) {	/* large tag */
4471da177e4SLinus Torvalds 			len = (p[2] << 8) | p[1];
4481da177e4SLinus Torvalds 			tag = p[0];
4491da177e4SLinus Torvalds 		} else {	/* small tag */
4501da177e4SLinus Torvalds 			len = p[0] & 0x07;
4511da177e4SLinus Torvalds 			tag = ((p[0] >> 3) & 0x0f);
4521da177e4SLinus Torvalds 		}
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 		switch (tag) {
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 		case LARGE_TAG_ANSISTR:
45750cbdaf1SJustin Stitt 			memcpy(dev->name, p + 3,
4589dd78466SBjorn Helgaas 			       len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
4599dd78466SBjorn Helgaas 			dev->name[len >=
4609dd78466SBjorn Helgaas 				  PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
4611da177e4SLinus Torvalds 			break;
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 		case SMALL_TAG_COMPATDEVID:	/* compatible ID */
4641da177e4SLinus Torvalds 			if (len != 4)
4651da177e4SLinus Torvalds 				goto len_err;
46625eb8461SBjorn Helgaas 			eisa_id = p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24;
46725eb8461SBjorn Helgaas 			pnp_eisa_id_to_string(eisa_id & PNP_EISA_ID_MASK, id);
468772defc6SBjorn Helgaas 			dev_id = pnp_add_id(dev, id);
469772defc6SBjorn Helgaas 			if (!dev_id)
470772defc6SBjorn Helgaas 				return NULL;
4711da177e4SLinus Torvalds 			break;
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds 		case SMALL_TAG_END:
4741da177e4SLinus Torvalds 			p = p + 2;
4751da177e4SLinus Torvalds 			return (unsigned char *)p;
4761da177e4SLinus Torvalds 			break;
4771da177e4SLinus Torvalds 
478af901ca1SAndré Goddard Rosa 		default:	/* an unknown tag */
4791da177e4SLinus Torvalds len_err:
480af11cb2dSBjorn Helgaas 			dev_err(&dev->dev, "unknown tag %#x length %d\n",
4819dd78466SBjorn Helgaas 				tag, len);
4821da177e4SLinus Torvalds 			break;
4831da177e4SLinus Torvalds 		}
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds 		/* continue to the next tag */
4861da177e4SLinus Torvalds 		if (p[0] & LARGE_TAG)
4871da177e4SLinus Torvalds 			p += len + 3;
4881da177e4SLinus Torvalds 		else
4891da177e4SLinus Torvalds 			p += len + 1;
4901da177e4SLinus Torvalds 	}
4911da177e4SLinus Torvalds 
492af11cb2dSBjorn Helgaas 	dev_err(&dev->dev, "no end tag in resource structure\n");
4931da177e4SLinus Torvalds 
4941da177e4SLinus Torvalds 	return NULL;
4951da177e4SLinus Torvalds }
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds /*
4981da177e4SLinus Torvalds  * Allocated Resource Encoding
4991da177e4SLinus Torvalds  */
5001da177e4SLinus Torvalds 
pnpbios_encode_mem(struct pnp_dev * dev,unsigned char * p,struct resource * res)50172dcc883SBjorn Helgaas static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p,
50272dcc883SBjorn Helgaas 			       struct resource *res)
5031da177e4SLinus Torvalds {
504aee3ad81SBjorn Helgaas 	unsigned long base;
505aee3ad81SBjorn Helgaas 	unsigned long len;
506aee3ad81SBjorn Helgaas 
507aee3ad81SBjorn Helgaas 	if (pnp_resource_enabled(res)) {
508aee3ad81SBjorn Helgaas 		base = res->start;
50928f65c11SJoe Perches 		len = resource_size(res);
510aee3ad81SBjorn Helgaas 	} else {
511aee3ad81SBjorn Helgaas 		base = 0;
512aee3ad81SBjorn Helgaas 		len = 0;
513aee3ad81SBjorn Helgaas 	}
51407d4e9afSBjorn Helgaas 
5151da177e4SLinus Torvalds 	p[4] = (base >> 8) & 0xff;
5161da177e4SLinus Torvalds 	p[5] = ((base >> 8) >> 8) & 0xff;
5171da177e4SLinus Torvalds 	p[6] = (base >> 8) & 0xff;
5181da177e4SLinus Torvalds 	p[7] = ((base >> 8) >> 8) & 0xff;
5191da177e4SLinus Torvalds 	p[10] = (len >> 8) & 0xff;
5201da177e4SLinus Torvalds 	p[11] = ((len >> 8) >> 8) & 0xff;
52172dcc883SBjorn Helgaas 
5222f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "  encode mem %#lx-%#lx\n", base, base + len - 1);
5231da177e4SLinus Torvalds }
5241da177e4SLinus Torvalds 
pnpbios_encode_mem32(struct pnp_dev * dev,unsigned char * p,struct resource * res)52572dcc883SBjorn Helgaas static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p,
52672dcc883SBjorn Helgaas 				 struct resource *res)
5271da177e4SLinus Torvalds {
528aee3ad81SBjorn Helgaas 	unsigned long base;
529aee3ad81SBjorn Helgaas 	unsigned long len;
530aee3ad81SBjorn Helgaas 
531aee3ad81SBjorn Helgaas 	if (pnp_resource_enabled(res)) {
532aee3ad81SBjorn Helgaas 		base = res->start;
53328f65c11SJoe Perches 		len = resource_size(res);
534aee3ad81SBjorn Helgaas 	} else {
535aee3ad81SBjorn Helgaas 		base = 0;
536aee3ad81SBjorn Helgaas 		len = 0;
537aee3ad81SBjorn Helgaas 	}
53807d4e9afSBjorn Helgaas 
5391da177e4SLinus Torvalds 	p[4] = base & 0xff;
5401da177e4SLinus Torvalds 	p[5] = (base >> 8) & 0xff;
5411da177e4SLinus Torvalds 	p[6] = (base >> 16) & 0xff;
5421da177e4SLinus Torvalds 	p[7] = (base >> 24) & 0xff;
5431da177e4SLinus Torvalds 	p[8] = base & 0xff;
5441da177e4SLinus Torvalds 	p[9] = (base >> 8) & 0xff;
5451da177e4SLinus Torvalds 	p[10] = (base >> 16) & 0xff;
5461da177e4SLinus Torvalds 	p[11] = (base >> 24) & 0xff;
5471da177e4SLinus Torvalds 	p[16] = len & 0xff;
5481da177e4SLinus Torvalds 	p[17] = (len >> 8) & 0xff;
5491da177e4SLinus Torvalds 	p[18] = (len >> 16) & 0xff;
5501da177e4SLinus Torvalds 	p[19] = (len >> 24) & 0xff;
55172dcc883SBjorn Helgaas 
5522f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "  encode mem32 %#lx-%#lx\n", base, base + len - 1);
5531da177e4SLinus Torvalds }
5541da177e4SLinus Torvalds 
pnpbios_encode_fixed_mem32(struct pnp_dev * dev,unsigned char * p,struct resource * res)55572dcc883SBjorn Helgaas static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p,
55672dcc883SBjorn Helgaas 				       struct resource *res)
5579dd78466SBjorn Helgaas {
558aee3ad81SBjorn Helgaas 	unsigned long base;
559aee3ad81SBjorn Helgaas 	unsigned long len;
560aee3ad81SBjorn Helgaas 
561aee3ad81SBjorn Helgaas 	if (pnp_resource_enabled(res)) {
562aee3ad81SBjorn Helgaas 		base = res->start;
56328f65c11SJoe Perches 		len = resource_size(res);
564aee3ad81SBjorn Helgaas 	} else {
565aee3ad81SBjorn Helgaas 		base = 0;
566aee3ad81SBjorn Helgaas 		len = 0;
567aee3ad81SBjorn Helgaas 	}
56807d4e9afSBjorn Helgaas 
5691da177e4SLinus Torvalds 	p[4] = base & 0xff;
5701da177e4SLinus Torvalds 	p[5] = (base >> 8) & 0xff;
5711da177e4SLinus Torvalds 	p[6] = (base >> 16) & 0xff;
5721da177e4SLinus Torvalds 	p[7] = (base >> 24) & 0xff;
5731da177e4SLinus Torvalds 	p[8] = len & 0xff;
5741da177e4SLinus Torvalds 	p[9] = (len >> 8) & 0xff;
5751da177e4SLinus Torvalds 	p[10] = (len >> 16) & 0xff;
5761da177e4SLinus Torvalds 	p[11] = (len >> 24) & 0xff;
57772dcc883SBjorn Helgaas 
5782f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "  encode fixed_mem32 %#lx-%#lx\n", base,
579aee3ad81SBjorn Helgaas 		base + len - 1);
5801da177e4SLinus Torvalds }
5811da177e4SLinus Torvalds 
pnpbios_encode_irq(struct pnp_dev * dev,unsigned char * p,struct resource * res)58272dcc883SBjorn Helgaas static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p,
58372dcc883SBjorn Helgaas 			       struct resource *res)
5841da177e4SLinus Torvalds {
585aee3ad81SBjorn Helgaas 	unsigned long map;
58607d4e9afSBjorn Helgaas 
587aee3ad81SBjorn Helgaas 	if (pnp_resource_enabled(res))
5881da177e4SLinus Torvalds 		map = 1 << res->start;
589aee3ad81SBjorn Helgaas 	else
590aee3ad81SBjorn Helgaas 		map = 0;
591aee3ad81SBjorn Helgaas 
5921da177e4SLinus Torvalds 	p[1] = map & 0xff;
5931da177e4SLinus Torvalds 	p[2] = (map >> 8) & 0xff;
59472dcc883SBjorn Helgaas 
5952f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "  encode irq mask %#lx\n", map);
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds 
pnpbios_encode_dma(struct pnp_dev * dev,unsigned char * p,struct resource * res)59872dcc883SBjorn Helgaas static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
59972dcc883SBjorn Helgaas 			       struct resource *res)
6001da177e4SLinus Torvalds {
601aee3ad81SBjorn Helgaas 	unsigned long map;
60207d4e9afSBjorn Helgaas 
603aee3ad81SBjorn Helgaas 	if (pnp_resource_enabled(res))
6041da177e4SLinus Torvalds 		map = 1 << res->start;
605aee3ad81SBjorn Helgaas 	else
606aee3ad81SBjorn Helgaas 		map = 0;
607aee3ad81SBjorn Helgaas 
6081da177e4SLinus Torvalds 	p[1] = map & 0xff;
60972dcc883SBjorn Helgaas 
6102f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "  encode dma mask %#lx\n", map);
6111da177e4SLinus Torvalds }
6121da177e4SLinus Torvalds 
pnpbios_encode_port(struct pnp_dev * dev,unsigned char * p,struct resource * res)61372dcc883SBjorn Helgaas static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
61472dcc883SBjorn Helgaas 				struct resource *res)
6151da177e4SLinus Torvalds {
616aee3ad81SBjorn Helgaas 	unsigned long base;
617aee3ad81SBjorn Helgaas 	unsigned long len;
618aee3ad81SBjorn Helgaas 
619aee3ad81SBjorn Helgaas 	if (pnp_resource_enabled(res)) {
620aee3ad81SBjorn Helgaas 		base = res->start;
62128f65c11SJoe Perches 		len = resource_size(res);
622aee3ad81SBjorn Helgaas 	} else {
623aee3ad81SBjorn Helgaas 		base = 0;
624aee3ad81SBjorn Helgaas 		len = 0;
625aee3ad81SBjorn Helgaas 	}
62607d4e9afSBjorn Helgaas 
6271da177e4SLinus Torvalds 	p[2] = base & 0xff;
6281da177e4SLinus Torvalds 	p[3] = (base >> 8) & 0xff;
6291da177e4SLinus Torvalds 	p[4] = base & 0xff;
6301da177e4SLinus Torvalds 	p[5] = (base >> 8) & 0xff;
6311da177e4SLinus Torvalds 	p[7] = len & 0xff;
63272dcc883SBjorn Helgaas 
6332f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "  encode io %#lx-%#lx\n", base, base + len - 1);
6341da177e4SLinus Torvalds }
6351da177e4SLinus Torvalds 
pnpbios_encode_fixed_port(struct pnp_dev * dev,unsigned char * p,struct resource * res)63672dcc883SBjorn Helgaas static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p,
63772dcc883SBjorn Helgaas 				      struct resource *res)
6381da177e4SLinus Torvalds {
6391da177e4SLinus Torvalds 	unsigned long base = res->start;
64028f65c11SJoe Perches 	unsigned long len = resource_size(res);
64107d4e9afSBjorn Helgaas 
642aee3ad81SBjorn Helgaas 	if (pnp_resource_enabled(res)) {
643aee3ad81SBjorn Helgaas 		base = res->start;
64428f65c11SJoe Perches 		len = resource_size(res);
645aee3ad81SBjorn Helgaas 	} else {
646aee3ad81SBjorn Helgaas 		base = 0;
647aee3ad81SBjorn Helgaas 		len = 0;
648aee3ad81SBjorn Helgaas 	}
649aee3ad81SBjorn Helgaas 
6501da177e4SLinus Torvalds 	p[1] = base & 0xff;
6511da177e4SLinus Torvalds 	p[2] = (base >> 8) & 0xff;
6521da177e4SLinus Torvalds 	p[3] = len & 0xff;
65372dcc883SBjorn Helgaas 
6542f53432cSBjorn Helgaas 	pnp_dbg(&dev->dev, "  encode fixed_io %#lx-%#lx\n", base,
655aee3ad81SBjorn Helgaas 		base + len - 1);
6561da177e4SLinus Torvalds }
6571da177e4SLinus Torvalds 
pnpbios_encode_allocated_resource_data(struct pnp_dev * dev,unsigned char * p,unsigned char * end)6584ab55d8dSBjorn Helgaas static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev
6594ab55d8dSBjorn Helgaas 								*dev,
6604ab55d8dSBjorn Helgaas 							     unsigned char *p,
6614ab55d8dSBjorn Helgaas 							     unsigned char *end)
6621da177e4SLinus Torvalds {
6631da177e4SLinus Torvalds 	unsigned int len, tag;
6641da177e4SLinus Torvalds 	int port = 0, irq = 0, dma = 0, mem = 0;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	if (!p)
6671da177e4SLinus Torvalds 		return NULL;
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 	while ((char *)p < (char *)end) {
6701da177e4SLinus Torvalds 
6711da177e4SLinus Torvalds 		/* determine the type of tag */
6721da177e4SLinus Torvalds 		if (p[0] & LARGE_TAG) {	/* large tag */
6731da177e4SLinus Torvalds 			len = (p[2] << 8) | p[1];
6741da177e4SLinus Torvalds 			tag = p[0];
6751da177e4SLinus Torvalds 		} else {	/* small tag */
6761da177e4SLinus Torvalds 			len = p[0] & 0x07;
6771da177e4SLinus Torvalds 			tag = ((p[0] >> 3) & 0x0f);
6781da177e4SLinus Torvalds 		}
6791da177e4SLinus Torvalds 
6801da177e4SLinus Torvalds 		switch (tag) {
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds 		case LARGE_TAG_MEM:
6831da177e4SLinus Torvalds 			if (len != 9)
6841da177e4SLinus Torvalds 				goto len_err;
6857e2cf31fSBjorn Helgaas 			pnpbios_encode_mem(dev, p,
6867e2cf31fSBjorn Helgaas 				pnp_get_resource(dev, IORESOURCE_MEM, mem));
6871da177e4SLinus Torvalds 			mem++;
6881da177e4SLinus Torvalds 			break;
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 		case LARGE_TAG_MEM32:
6911da177e4SLinus Torvalds 			if (len != 17)
6921da177e4SLinus Torvalds 				goto len_err;
6937e2cf31fSBjorn Helgaas 			pnpbios_encode_mem32(dev, p,
6947e2cf31fSBjorn Helgaas 				pnp_get_resource(dev, IORESOURCE_MEM, mem));
6951da177e4SLinus Torvalds 			mem++;
6961da177e4SLinus Torvalds 			break;
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 		case LARGE_TAG_FIXEDMEM32:
6991da177e4SLinus Torvalds 			if (len != 9)
7001da177e4SLinus Torvalds 				goto len_err;
7017e2cf31fSBjorn Helgaas 			pnpbios_encode_fixed_mem32(dev, p,
7027e2cf31fSBjorn Helgaas 				pnp_get_resource(dev, IORESOURCE_MEM, mem));
7031da177e4SLinus Torvalds 			mem++;
7041da177e4SLinus Torvalds 			break;
7051da177e4SLinus Torvalds 
7061da177e4SLinus Torvalds 		case SMALL_TAG_IRQ:
7071da177e4SLinus Torvalds 			if (len < 2 || len > 3)
7081da177e4SLinus Torvalds 				goto len_err;
7097e2cf31fSBjorn Helgaas 			pnpbios_encode_irq(dev, p,
7107e2cf31fSBjorn Helgaas 				pnp_get_resource(dev, IORESOURCE_IRQ, irq));
7111da177e4SLinus Torvalds 			irq++;
7121da177e4SLinus Torvalds 			break;
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 		case SMALL_TAG_DMA:
7151da177e4SLinus Torvalds 			if (len != 2)
7161da177e4SLinus Torvalds 				goto len_err;
7177e2cf31fSBjorn Helgaas 			pnpbios_encode_dma(dev, p,
7187e2cf31fSBjorn Helgaas 				pnp_get_resource(dev, IORESOURCE_DMA, dma));
7191da177e4SLinus Torvalds 			dma++;
7201da177e4SLinus Torvalds 			break;
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 		case SMALL_TAG_PORT:
7231da177e4SLinus Torvalds 			if (len != 7)
7241da177e4SLinus Torvalds 				goto len_err;
7257e2cf31fSBjorn Helgaas 			pnpbios_encode_port(dev, p,
7267e2cf31fSBjorn Helgaas 				pnp_get_resource(dev, IORESOURCE_IO, port));
7271da177e4SLinus Torvalds 			port++;
7281da177e4SLinus Torvalds 			break;
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds 		case SMALL_TAG_VENDOR:
7311da177e4SLinus Torvalds 			/* do nothing */
7321da177e4SLinus Torvalds 			break;
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 		case SMALL_TAG_FIXEDPORT:
7351da177e4SLinus Torvalds 			if (len != 3)
7361da177e4SLinus Torvalds 				goto len_err;
7377e2cf31fSBjorn Helgaas 			pnpbios_encode_fixed_port(dev, p,
7387e2cf31fSBjorn Helgaas 				pnp_get_resource(dev, IORESOURCE_IO, port));
7391da177e4SLinus Torvalds 			port++;
7401da177e4SLinus Torvalds 			break;
7411da177e4SLinus Torvalds 
7421da177e4SLinus Torvalds 		case SMALL_TAG_END:
7431da177e4SLinus Torvalds 			p = p + 2;
7441da177e4SLinus Torvalds 			return (unsigned char *)p;
7451da177e4SLinus Torvalds 			break;
7461da177e4SLinus Torvalds 
747af901ca1SAndré Goddard Rosa 		default:	/* an unknown tag */
7481da177e4SLinus Torvalds len_err:
749af11cb2dSBjorn Helgaas 			dev_err(&dev->dev, "unknown tag %#x length %d\n",
7509dd78466SBjorn Helgaas 				tag, len);
7511da177e4SLinus Torvalds 			break;
7521da177e4SLinus Torvalds 		}
7531da177e4SLinus Torvalds 
7541da177e4SLinus Torvalds 		/* continue to the next tag */
7551da177e4SLinus Torvalds 		if (p[0] & LARGE_TAG)
7561da177e4SLinus Torvalds 			p += len + 3;
7571da177e4SLinus Torvalds 		else
7581da177e4SLinus Torvalds 			p += len + 1;
7591da177e4SLinus Torvalds 	}
7601da177e4SLinus Torvalds 
761af11cb2dSBjorn Helgaas 	dev_err(&dev->dev, "no end tag in resource structure\n");
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds 	return NULL;
7641da177e4SLinus Torvalds }
7651da177e4SLinus Torvalds 
7661da177e4SLinus Torvalds /*
7671da177e4SLinus Torvalds  * Core Parsing Functions
7681da177e4SLinus Torvalds  */
7691da177e4SLinus Torvalds 
pnpbios_parse_data_stream(struct pnp_dev * dev,struct pnp_bios_node * node)7702bb9a6b3SThomas Renninger int __init pnpbios_parse_data_stream(struct pnp_dev *dev,
7712bb9a6b3SThomas Renninger 					struct pnp_bios_node *node)
7721da177e4SLinus Torvalds {
7731da177e4SLinus Torvalds 	unsigned char *p = (char *)node->data;
7741da177e4SLinus Torvalds 	unsigned char *end = (char *)(node->data + node->size);
77507d4e9afSBjorn Helgaas 
7764ab55d8dSBjorn Helgaas 	p = pnpbios_parse_allocated_resource_data(dev, p, end);
7771da177e4SLinus Torvalds 	if (!p)
7781da177e4SLinus Torvalds 		return -EIO;
7791da177e4SLinus Torvalds 	p = pnpbios_parse_resource_option_data(p, end, dev);
7801da177e4SLinus Torvalds 	if (!p)
7811da177e4SLinus Torvalds 		return -EIO;
7821da177e4SLinus Torvalds 	p = pnpbios_parse_compatible_ids(p, end, dev);
7831da177e4SLinus Torvalds 	if (!p)
7841da177e4SLinus Torvalds 		return -EIO;
7851da177e4SLinus Torvalds 	return 0;
7861da177e4SLinus Torvalds }
7871da177e4SLinus Torvalds 
pnpbios_read_resources_from_node(struct pnp_dev * dev,struct pnp_bios_node * node)7884ab55d8dSBjorn Helgaas int pnpbios_read_resources_from_node(struct pnp_dev *dev,
7891da177e4SLinus Torvalds 				     struct pnp_bios_node *node)
7901da177e4SLinus Torvalds {
7911da177e4SLinus Torvalds 	unsigned char *p = (char *)node->data;
7921da177e4SLinus Torvalds 	unsigned char *end = (char *)(node->data + node->size);
79307d4e9afSBjorn Helgaas 
7944ab55d8dSBjorn Helgaas 	p = pnpbios_parse_allocated_resource_data(dev, p, end);
7951da177e4SLinus Torvalds 	if (!p)
7961da177e4SLinus Torvalds 		return -EIO;
7971da177e4SLinus Torvalds 	return 0;
7981da177e4SLinus Torvalds }
7991da177e4SLinus Torvalds 
pnpbios_write_resources_to_node(struct pnp_dev * dev,struct pnp_bios_node * node)8004ab55d8dSBjorn Helgaas int pnpbios_write_resources_to_node(struct pnp_dev *dev,
8011da177e4SLinus Torvalds 				    struct pnp_bios_node *node)
8021da177e4SLinus Torvalds {
8031da177e4SLinus Torvalds 	unsigned char *p = (char *)node->data;
8041da177e4SLinus Torvalds 	unsigned char *end = (char *)(node->data + node->size);
80507d4e9afSBjorn Helgaas 
8064ab55d8dSBjorn Helgaas 	p = pnpbios_encode_allocated_resource_data(dev, p, end);
8071da177e4SLinus Torvalds 	if (!p)
8081da177e4SLinus Torvalds 		return -EIO;
8091da177e4SLinus Torvalds 	return 0;
8101da177e4SLinus Torvalds }
811