Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.21 212 lines 5.2 kB view raw
1/* 2 * i8259 interrupt controller driver. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 */ 9#include <linux/init.h> 10#include <linux/ioport.h> 11#include <linux/interrupt.h> 12#include <asm/io.h> 13#include <asm/i8259.h> 14 15static volatile void __iomem *pci_intack; /* RO, gives us the irq vector */ 16 17static unsigned char cached_8259[2] = { 0xff, 0xff }; 18#define cached_A1 (cached_8259[0]) 19#define cached_21 (cached_8259[1]) 20 21static DEFINE_SPINLOCK(i8259_lock); 22 23static int i8259_pic_irq_offset; 24 25/* 26 * Acknowledge the IRQ using either the PCI host bridge's interrupt 27 * acknowledge feature or poll. How i8259_init() is called determines 28 * which is called. It should be noted that polling is broken on some 29 * IBM and Motorola PReP boxes so we must use the int-ack feature on them. 30 */ 31int i8259_irq(void) 32{ 33 int irq; 34 35 spin_lock(&i8259_lock); 36 37 /* Either int-ack or poll for the IRQ */ 38 if (pci_intack) 39 irq = readb(pci_intack); 40 else { 41 /* Perform an interrupt acknowledge cycle on controller 1. */ 42 outb(0x0C, 0x20); /* prepare for poll */ 43 irq = inb(0x20) & 7; 44 if (irq == 2 ) { 45 /* 46 * Interrupt is cascaded so perform interrupt 47 * acknowledge on controller 2. 48 */ 49 outb(0x0C, 0xA0); /* prepare for poll */ 50 irq = (inb(0xA0) & 7) + 8; 51 } 52 } 53 54 if (irq == 7) { 55 /* 56 * This may be a spurious interrupt. 57 * 58 * Read the interrupt status register (ISR). If the most 59 * significant bit is not set then there is no valid 60 * interrupt. 61 */ 62 if (!pci_intack) 63 outb(0x0B, 0x20); /* ISR register */ 64 if(~inb(0x20) & 0x80) 65 irq = -1; 66 } 67 68 spin_unlock(&i8259_lock); 69 return irq + i8259_pic_irq_offset; 70} 71 72static void i8259_mask_and_ack_irq(unsigned int irq_nr) 73{ 74 unsigned long flags; 75 76 spin_lock_irqsave(&i8259_lock, flags); 77 irq_nr -= i8259_pic_irq_offset; 78 if (irq_nr > 7) { 79 cached_A1 |= 1 << (irq_nr-8); 80 inb(0xA1); /* DUMMY */ 81 outb(cached_A1, 0xA1); 82 outb(0x20, 0xA0); /* Non-specific EOI */ 83 outb(0x20, 0x20); /* Non-specific EOI to cascade */ 84 } else { 85 cached_21 |= 1 << irq_nr; 86 inb(0x21); /* DUMMY */ 87 outb(cached_21, 0x21); 88 outb(0x20, 0x20); /* Non-specific EOI */ 89 } 90 spin_unlock_irqrestore(&i8259_lock, flags); 91} 92 93static void i8259_set_irq_mask(int irq_nr) 94{ 95 outb(cached_A1,0xA1); 96 outb(cached_21,0x21); 97} 98 99static void i8259_mask_irq(unsigned int irq_nr) 100{ 101 unsigned long flags; 102 103 spin_lock_irqsave(&i8259_lock, flags); 104 irq_nr -= i8259_pic_irq_offset; 105 if (irq_nr < 8) 106 cached_21 |= 1 << irq_nr; 107 else 108 cached_A1 |= 1 << (irq_nr-8); 109 i8259_set_irq_mask(irq_nr); 110 spin_unlock_irqrestore(&i8259_lock, flags); 111} 112 113static void i8259_unmask_irq(unsigned int irq_nr) 114{ 115 unsigned long flags; 116 117 spin_lock_irqsave(&i8259_lock, flags); 118 irq_nr -= i8259_pic_irq_offset; 119 if (irq_nr < 8) 120 cached_21 &= ~(1 << irq_nr); 121 else 122 cached_A1 &= ~(1 << (irq_nr-8)); 123 i8259_set_irq_mask(irq_nr); 124 spin_unlock_irqrestore(&i8259_lock, flags); 125} 126 127static struct irq_chip i8259_pic = { 128 .typename = " i8259 ", 129 .mask = i8259_mask_irq, 130 .unmask = i8259_unmask_irq, 131 .mask_ack = i8259_mask_and_ack_irq, 132}; 133 134static struct resource pic1_iores = { 135 .name = "8259 (master)", 136 .start = 0x20, 137 .end = 0x21, 138 .flags = IORESOURCE_BUSY, 139}; 140 141static struct resource pic2_iores = { 142 .name = "8259 (slave)", 143 .start = 0xa0, 144 .end = 0xa1, 145 .flags = IORESOURCE_BUSY, 146}; 147 148static struct resource pic_edgectrl_iores = { 149 .name = "8259 edge control", 150 .start = 0x4d0, 151 .end = 0x4d1, 152 .flags = IORESOURCE_BUSY, 153}; 154 155static struct irqaction i8259_irqaction = { 156 .handler = no_action, 157 .flags = IRQF_DISABLED, 158 .mask = CPU_MASK_NONE, 159 .name = "82c59 secondary cascade", 160}; 161 162/* 163 * i8259_init() 164 * intack_addr - PCI interrupt acknowledge (real) address which will return 165 * the active irq from the 8259 166 */ 167void __init i8259_init(unsigned long intack_addr, int offset) 168{ 169 unsigned long flags; 170 int i; 171 172 spin_lock_irqsave(&i8259_lock, flags); 173 i8259_pic_irq_offset = offset; 174 175 /* init master interrupt controller */ 176 outb(0x11, 0x20); /* Start init sequence */ 177 outb(0x00, 0x21); /* Vector base */ 178 outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ 179 outb(0x01, 0x21); /* Select 8086 mode */ 180 181 /* init slave interrupt controller */ 182 outb(0x11, 0xA0); /* Start init sequence */ 183 outb(0x08, 0xA1); /* Vector base */ 184 outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ 185 outb(0x01, 0xA1); /* Select 8086 mode */ 186 187 /* always read ISR */ 188 outb(0x0B, 0x20); 189 outb(0x0B, 0xA0); 190 191 /* Mask all interrupts */ 192 outb(cached_A1, 0xA1); 193 outb(cached_21, 0x21); 194 195 spin_unlock_irqrestore(&i8259_lock, flags); 196 197 for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) { 198 set_irq_chip_and_handler(offset + i, &i8259_pic, 199 handle_level_irq); 200 irq_desc[offset + i].status |= IRQ_LEVEL; 201 } 202 203 /* reserve our resources */ 204 setup_irq(offset + 2, &i8259_irqaction); 205 request_resource(&ioport_resource, &pic1_iores); 206 request_resource(&ioport_resource, &pic2_iores); 207 request_resource(&ioport_resource, &pic_edgectrl_iores); 208 209 if (intack_addr != 0) 210 pci_intack = ioremap(intack_addr, 1); 211 212}