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