/*
* rsparser.c - parses and encodes pnpbios resource data streams
*/
#include <linux/ctype.h>
#include <linux/pnp.h>
#include <linux/pnpbios.h>
#include <linux/string.h>
#include <linux/slab.h>
#ifdef CONFIG_PCI
#include <linux/pci.h>
#else
inline void pcibios_penalize_isa_irq(int irq, int active)
{
}
#endif /* CONFIG_PCI */
#include "../base.h"
#include "pnpbios.h"
/* standard resource tags */
#define SMALL_TAG_PNPVERNO 0x01
#define SMALL_TAG_LOGDEVID 0x02
#define SMALL_TAG_COMPATDEVID 0x03
#define SMALL_TAG_IRQ 0x04
#define SMALL_TAG_DMA 0x05
#define SMALL_TAG_STARTDEP 0x06
#define SMALL_TAG_ENDDEP 0x07
#define SMALL_TAG_PORT 0x08
#define SMALL_TAG_FIXEDPORT 0x09
#define SMALL_TAG_VENDOR 0x0e
#define SMALL_TAG_END 0x0f
#define LARGE_TAG 0x80
#define LARGE_TAG_MEM 0x81
#define LARGE_TAG_ANSISTR 0x82
#define LARGE_TAG_UNICODESTR 0x83
#define LARGE_TAG_VENDOR 0x84
#define LARGE_TAG_MEM32 0x85
#define LARGE_TAG_FIXEDMEM32 0x86
/*
* Resource Data Stream Format:
*
* Allocated Resources (required)
* end tag ->
* Resource Configuration Options (optional)
* end tag ->
* Compitable Device IDs (optional)
* final end tag ->
*/
/*
* Allocated Resources
*/
static void pnpbios_parse_allocated_dmaresource(struct pnp_dev *dev, int dma)
{
struct resource *res;
int i;
for (i = 0; i < PNP_MAX_DMA; i++) {
res = pnp_get_resource(dev, IORESOURCE_DMA, i);
if (!pnp_resource_valid(res))
break;
}
if (i < PNP_MAX_DMA) {
res->flags = IORESOURCE_DMA; // Also clears _UNSET flag
if (dma == -1) {
res->flags |= IORESOURCE_DISABLED;
return;
}
res->start = res->end = (unsigned long)dma;
}
}
static void pnpbios_parse_allocated_ioresource(struct pnp_dev *dev,
int io, int len)
{
struct resource *res;
int i;
for (i = 0; i < PNP_MAX_PORT; i++) {
res = pnp_get_resource(dev, IORESOURCE_IO, i);
if (!pnp_resource_valid(res))
break;
}
if (i < PNP_MAX_PORT) {
res->flags = IORESOURCE_IO; // Also clears _UNSET flag
if (len <= 0 || (io + len - 1) >= 0x10003) {
res->flags |= IORESOURCE_DISABLED;
return;
}
res->start = (unsigned long)io;
res->end = (unsigned long)(io + len - 1);
}
}
static void pnpbios_parse_allocated_memresource(struct pnp_dev *dev,
int mem, int len)
{
struct resource *res;
int i;
for (i = 0; i < PNP_MAX_MEM; i++) {
res = pnp_get_resource(dev, IORESOURCE_MEM, i);
if (!pnp_resource_valid(res))
break;
}
if (i < PNP_MAX_MEM) {
res->flags = IORESOURCE_MEM; // Also clears _UNSET flag
if (len <= 0) {
res->flags |= IORESOURCE_DISABLED;
return;
}
res->start = (unsigned long)mem;
res->end = (unsigned long)(mem + len - 1);
}
}
static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev,
unsigned char *p,
unsigned char *end)
{
unsigned int len, tag;
int io, size, mask, i, flags;
if (!p)
return NULL;
dev_dbg(&dev->dev, "parse allocated resources\n");
pnp_init_resources(dev);
while ((char *)p < (char *)end) {
/* determine the type of tag */
if (p[0] & LARGE_TAG) { /* large tag */
len = (p[2] << 8) | p[1];
tag = p[0];
} else { /* small tag */
len = p[0] & 0x07;
tag = ((p[0] >> 3) & 0x0f);
}
switch (tag) {
case LARGE_TAG_MEM:
if (len != 9)
goto len_err;
io = *(short *)&p[4];
size = *(short *)&p[10];
pnpbios_parse_allocated_memresource(dev, io, size);
break;
case LARGE_TAG_ANSISTR:
/* ignore this for now */
break;
case LARGE_TAG_VENDOR:
/* do nothing */
break;
case LARGE_TAG_MEM32:
if (len != 17)
goto len_err;
io = *(int *)&p[4];
size = *(int *)&p[16];
pnpbios_parse_allocated_memresource(dev, io, size);
break;
case LARGE_TAG_FIXEDMEM32:
if (len != 9)
goto len_err;
io = *(int *)&p[4];
size = *(int *)&p[8];
pnpbios_parse_allocated_memresource(dev, io, size);
break;
case SMALL_TAG_IRQ:
if (len < 2 || len > 3)