/*
* pnpacpi -- PnP ACPI driver
*
* Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
* Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
#include "pnpacpi.h"
#ifdef CONFIG_IA64
#define valid_IRQ(i) (1)
#else
#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
#endif
/*
* Allocated Resources
*/
static int irq_flags(int triggering, int polarity, int shareable)
{
int flags;
if (triggering == ACPI_LEVEL_SENSITIVE) {
if (polarity == ACPI_ACTIVE_LOW)
flags = IORESOURCE_IRQ_LOWLEVEL;
else
flags = IORESOURCE_IRQ_HIGHLEVEL;
} else {
if (polarity == ACPI_ACTIVE_LOW)
flags = IORESOURCE_IRQ_LOWEDGE;
else
flags = IORESOURCE_IRQ_HIGHEDGE;
}
if (shareable)
flags |= IORESOURCE_IRQ_SHAREABLE;
return flags;
}
static void decode_irq_flags(int flag, int *triggering, int *polarity)
{
switch (flag) {
case IORESOURCE_IRQ_LOWLEVEL:
*triggering = ACPI_LEVEL_SENSITIVE;
*polarity = ACPI_ACTIVE_LOW;
break;
case IORESOURCE_IRQ_HIGHLEVEL:
*triggering = ACPI_LEVEL_SENSITIVE;
*polarity = ACPI_ACTIVE_HIGH;
break;
case IORESOURCE_IRQ_LOWEDGE:
*triggering = ACPI_EDGE_SENSITIVE;
*polarity = ACPI_ACTIVE_LOW;
break;
case IORESOURCE_IRQ_HIGHEDGE:
*triggering = ACPI_EDGE_SENSITIVE;
*polarity = ACPI_ACTIVE_HIGH;
break;
}
}
static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
u32 gsi, int triggering,
int polarity, int shareable)
{
struct pnp_resource_table *res = &dev->res;
int i = 0;
int irq;
int p, t;
static unsigned char warned;
if (!valid_IRQ(gsi))
return;
while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
i < PNP_MAX_IRQ)
i++;
if (i >= PNP_MAX_IRQ) {
if (!warned) {
printk(KERN_WARNING "pnpacpi: exceeded the max number"
" of IRQ resources: %d\n", PNP_MAX_IRQ);
warned = 1;
}
return;
}
/*
* in IO-APIC mode, use overrided attribute. Two reasons:
* 1. BIOS bug in DSDT
* 2. BIOS uses IO-APIC mode Interrupt Source Override
*/
if (!acpi_get_override_irq(gsi, &t, &p)) {
t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
if (triggering != t || polarity != p) {
dev_warn(&dev->dev, "IRQ %d override to %s, %s\n",
gsi, t ? "edge":"level", p ? "low":"high");
triggering = t;
polarity = p;
}
}
res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
res->irq_resource[i].flags |= irq_flags(triggering, polarity, shareable);
irq = acpi_register_gsi(gsi, triggering, polarity);
if (irq < 0) {
res->irq_resource[i].flags |= IORESOURCE_DISABLED;
return;
}
res->irq_resource[i].start = irq;
res->irq_resource[i].end = irq;
pcibios_penalize_isa_irq(irq, 1