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