1 /* 2 * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file COPYING in the main directory of this archive 6 * for more details. 7 */ 8 9 #include <linux/init.h> 10 #include <linux/interrupt.h> 11 #include <linux/errno.h> 12 13 #include <asm/irq.h> 14 #include <asm/traps.h> 15 #include <asm/amigahw.h> 16 #include <asm/amigaints.h> 17 #include <asm/amipcmcia.h> 18 19 static void amiga_irq_enable(struct irq_data *data); 20 static void amiga_irq_disable(struct irq_data *data); 21 static irqreturn_t ami_int1(int irq, void *dev_id); 22 static irqreturn_t ami_int3(int irq, void *dev_id); 23 static irqreturn_t ami_int4(int irq, void *dev_id); 24 static irqreturn_t ami_int5(int irq, void *dev_id); 25 26 static struct irq_chip amiga_irq_chip = { 27 .name = "amiga", 28 .irq_enable = amiga_irq_enable, 29 .irq_disable = amiga_irq_disable, 30 }; 31 32 /* 33 * void amiga_init_IRQ(void) 34 * 35 * Parameters: None 36 * 37 * Returns: Nothing 38 * 39 * This function should be called during kernel startup to initialize 40 * the amiga IRQ handling routines. 41 */ 42 43 void __init amiga_init_IRQ(void) 44 { 45 if (request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL)) 46 pr_err("Couldn't register int%d\n", 1); 47 if (request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL)) 48 pr_err("Couldn't register int%d\n", 3); 49 if (request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL)) 50 pr_err("Couldn't register int%d\n", 4); 51 if (request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL)) 52 pr_err("Couldn't register int%d\n", 5); 53 54 m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER, 55 AMI_STD_IRQS); 56 57 /* turn off PCMCIA interrupts */ 58 if (AMIGAHW_PRESENT(PCMCIA)) 59 gayle.inten = GAYLE_IRQ_IDE; 60 61 /* turn off all interrupts and enable the master interrupt bit */ 62 amiga_custom.intena = 0x7fff; 63 amiga_custom.intreq = 0x7fff; 64 amiga_custom.intena = IF_SETCLR | IF_INTEN; 65 66 cia_init_IRQ(&ciaa_base); 67 cia_init_IRQ(&ciab_base); 68 } 69 70 /* 71 * Enable/disable a particular machine specific interrupt source. 72 * Note that this may affect other interrupts in case of a shared interrupt. 73 * This function should only be called for a _very_ short time to change some 74 * internal data, that may not be changed by the interrupt at the same time. 75 */ 76 77 static void amiga_irq_enable(struct irq_data *data) 78 { 79 amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER)); 80 } 81 82 static void amiga_irq_disable(struct irq_data *data) 83 { 84 amiga_custom.intena = 1 << (data->irq - IRQ_USER); 85 } 86 87 /* 88 * The builtin Amiga hardware interrupt handlers. 89 */ 90 91 static irqreturn_t ami_int1(int irq, void *dev_id) 92 { 93 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; 94 95 /* if serial transmit buffer empty, interrupt */ 96 if (ints & IF_TBE) { 97 amiga_custom.intreq = IF_TBE; 98 generic_handle_irq(IRQ_AMIGA_TBE); 99 } 100 101 /* if floppy disk transfer complete, interrupt */ 102 if (ints & IF_DSKBLK) { 103 amiga_custom.intreq = IF_DSKBLK; 104 generic_handle_irq(IRQ_AMIGA_DSKBLK); 105 } 106 107 /* if software interrupt set, interrupt */ 108 if (ints & IF_SOFT) { 109 amiga_custom.intreq = IF_SOFT; 110 generic_handle_irq(IRQ_AMIGA_SOFT); 111 } 112 return IRQ_HANDLED; 113 } 114 115 static irqreturn_t ami_int3(int irq, void *dev_id) 116 { 117 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; 118 119 /* if a blitter interrupt */ 120 if (ints & IF_BLIT) { 121 amiga_custom.intreq = IF_BLIT; 122 generic_handle_irq(IRQ_AMIGA_BLIT); 123 } 124 125 /* if a copper interrupt */ 126 if (ints & IF_COPER) { 127 amiga_custom.intreq = IF_COPER; 128 generic_handle_irq(IRQ_AMIGA_COPPER); 129 } 130 131 /* if a vertical blank interrupt */ 132 if (ints & IF_VERTB) { 133 amiga_custom.intreq = IF_VERTB; 134 generic_handle_irq(IRQ_AMIGA_VERTB); 135 } 136 return IRQ_HANDLED; 137 } 138 139 static irqreturn_t ami_int4(int irq, void *dev_id) 140 { 141 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; 142 143 /* if audio 0 interrupt */ 144 if (ints & IF_AUD0) { 145 amiga_custom.intreq = IF_AUD0; 146 generic_handle_irq(IRQ_AMIGA_AUD0); 147 } 148 149 /* if audio 1 interrupt */ 150 if (ints & IF_AUD1) { 151 amiga_custom.intreq = IF_AUD1; 152 generic_handle_irq(IRQ_AMIGA_AUD1); 153 } 154 155 /* if audio 2 interrupt */ 156 if (ints & IF_AUD2) { 157 amiga_custom.intreq = IF_AUD2; 158 generic_handle_irq(IRQ_AMIGA_AUD2); 159 } 160 161 /* if audio 3 interrupt */ 162 if (ints & IF_AUD3) { 163 amiga_custom.intreq = IF_AUD3; 164 generic_handle_irq(IRQ_AMIGA_AUD3); 165 } 166 return IRQ_HANDLED; 167 } 168 169 static irqreturn_t ami_int5(int irq, void *dev_id) 170 { 171 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; 172 173 /* if serial receive buffer full interrupt */ 174 if (ints & IF_RBF) { 175 /* acknowledge of IF_RBF must be done by the serial interrupt */ 176 generic_handle_irq(IRQ_AMIGA_RBF); 177 } 178 179 /* if a disk sync interrupt */ 180 if (ints & IF_DSKSYN) { 181 amiga_custom.intreq = IF_DSKSYN; 182 generic_handle_irq(IRQ_AMIGA_DSKSYN); 183 } 184 return IRQ_HANDLED; 185 } 186