#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/sysdev.h>
+#include <linux/bitops.h>
#include <asm/acpi.h>
#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hw_irq.h>
-#include <asm/bitops.h>
#include <asm/pgtable.h>
#include <asm/delay.h>
#include <asm/desc.h>
* moves to arch independent land
*/
-spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(i8259A_lock);
static void end_8259A_irq (unsigned int irq)
{
#define shutdown_8259A_irq disable_8259A_irq
-void mask_and_ack_8259A(unsigned int);
+static void mask_and_ack_8259A(unsigned int);
static unsigned int startup_8259A_irq(unsigned int irq)
{
* first, _then_ send the EOI, and the order of EOI
* to the two 8259s is important!
*/
-void mask_and_ack_8259A(unsigned int irq)
+static void mask_and_ack_8259A(unsigned int irq)
{
unsigned int irqmask = 1 << irq;
unsigned long flags;
* lets ACK and report it. [once per IRQ]
*/
if (!(spurious_irq_mask & irqmask)) {
- printk("spurious 8259A interrupt: IRQ%d.\n", irq);
+ printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
spurious_irq_mask |= irqmask;
}
atomic_inc(&irq_err_count);
}
}
-void __init init_8259A(int auto_eoi)
+void init_8259A(int auto_eoi)
{
unsigned long flags;
spin_unlock_irqrestore(&i8259A_lock, flags);
}
+static char irq_trigger[2];
+/**
+ * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ
+ */
+static void restore_ELCR(char *trigger)
+{
+ outb(trigger[0], 0x4d0);
+ outb(trigger[1], 0x4d1);
+}
+
+static void save_ELCR(char *trigger)
+{
+ /* IRQ 0,1,2,8,13 are marked as reserved */
+ trigger[0] = inb(0x4d0) & 0xF8;
+ trigger[1] = inb(0x4d1) & 0xDE;
+}
+
+static int i8259A_resume(struct sys_device *dev)
+{
+ init_8259A(0);
+ restore_ELCR(irq_trigger);
+ return 0;
+}
+
+static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
+{
+ save_ELCR(irq_trigger);
+ return 0;
+}
+
+static struct sysdev_class i8259_sysdev_class = {
+ set_kset_name("i8259"),
+ .suspend = i8259A_suspend,
+ .resume = i8259A_resume,
+};
+
+static struct sys_device device_i8259A = {
+ .id = 0,
+ .cls = &i8259_sysdev_class,
+};
+
+static int __init i8259A_init_sysfs(void)
+{
+ int error = sysdev_class_register(&i8259_sysdev_class);
+ if (!error)
+ error = sysdev_register(&device_i8259A);
+ return error;
+}
+
+device_initcall(i8259A_init_sysfs);
+
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
void reschedule_interrupt(void);
void call_function_interrupt(void);
void invalidate_interrupt(void);
+void thermal_interrupt(void);
+void i8254_timer_resume(void);
static void setup_timer(void)
{
return 0;
}
+void i8254_timer_resume(void)
+{
+ setup_timer();
+}
+
static struct sysdev_class timer_sysclass = {
set_kset_name("timer"),
.resume = timer_resume,
/* IPI for generic function call */
set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
#endif
+ set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
#ifdef CONFIG_X86_LOCAL_APIC
/* self generated IPI for local APIC timer */