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