forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
4.0 KiB
174 lines
4.0 KiB
/* |
|
* Amiga Linux interrupt handling code |
|
* |
|
* This file is subject to the terms and conditions of the GNU General Public |
|
* License. See the file COPYING in the main directory of this archive |
|
* for more details. |
|
*/ |
|
|
|
#include <linux/init.h> |
|
#include <linux/interrupt.h> |
|
#include <linux/errno.h> |
|
#include <linux/irq.h> |
|
|
|
#include <asm/irq.h> |
|
#include <asm/traps.h> |
|
#include <asm/amigahw.h> |
|
#include <asm/amigaints.h> |
|
#include <asm/amipcmcia.h> |
|
|
|
|
|
/* |
|
* Enable/disable a particular machine specific interrupt source. |
|
* Note that this may affect other interrupts in case of a shared interrupt. |
|
* This function should only be called for a _very_ short time to change some |
|
* internal data, that may not be changed by the interrupt at the same time. |
|
*/ |
|
|
|
static void amiga_irq_enable(struct irq_data *data) |
|
{ |
|
amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER)); |
|
} |
|
|
|
static void amiga_irq_disable(struct irq_data *data) |
|
{ |
|
amiga_custom.intena = 1 << (data->irq - IRQ_USER); |
|
} |
|
|
|
static struct irq_chip amiga_irq_chip = { |
|
.name = "amiga", |
|
.irq_enable = amiga_irq_enable, |
|
.irq_disable = amiga_irq_disable, |
|
}; |
|
|
|
|
|
/* |
|
* The builtin Amiga hardware interrupt handlers. |
|
*/ |
|
|
|
static void ami_int1(struct irq_desc *desc) |
|
{ |
|
unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
|
|
|
/* if serial transmit buffer empty, interrupt */ |
|
if (ints & IF_TBE) { |
|
amiga_custom.intreq = IF_TBE; |
|
generic_handle_irq(IRQ_AMIGA_TBE); |
|
} |
|
|
|
/* if floppy disk transfer complete, interrupt */ |
|
if (ints & IF_DSKBLK) { |
|
amiga_custom.intreq = IF_DSKBLK; |
|
generic_handle_irq(IRQ_AMIGA_DSKBLK); |
|
} |
|
|
|
/* if software interrupt set, interrupt */ |
|
if (ints & IF_SOFT) { |
|
amiga_custom.intreq = IF_SOFT; |
|
generic_handle_irq(IRQ_AMIGA_SOFT); |
|
} |
|
} |
|
|
|
static void ami_int3(struct irq_desc *desc) |
|
{ |
|
unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
|
|
|
/* if a blitter interrupt */ |
|
if (ints & IF_BLIT) { |
|
amiga_custom.intreq = IF_BLIT; |
|
generic_handle_irq(IRQ_AMIGA_BLIT); |
|
} |
|
|
|
/* if a copper interrupt */ |
|
if (ints & IF_COPER) { |
|
amiga_custom.intreq = IF_COPER; |
|
generic_handle_irq(IRQ_AMIGA_COPPER); |
|
} |
|
|
|
/* if a vertical blank interrupt */ |
|
if (ints & IF_VERTB) { |
|
amiga_custom.intreq = IF_VERTB; |
|
generic_handle_irq(IRQ_AMIGA_VERTB); |
|
} |
|
} |
|
|
|
static void ami_int4(struct irq_desc *desc) |
|
{ |
|
unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
|
|
|
/* if audio 0 interrupt */ |
|
if (ints & IF_AUD0) { |
|
amiga_custom.intreq = IF_AUD0; |
|
generic_handle_irq(IRQ_AMIGA_AUD0); |
|
} |
|
|
|
/* if audio 1 interrupt */ |
|
if (ints & IF_AUD1) { |
|
amiga_custom.intreq = IF_AUD1; |
|
generic_handle_irq(IRQ_AMIGA_AUD1); |
|
} |
|
|
|
/* if audio 2 interrupt */ |
|
if (ints & IF_AUD2) { |
|
amiga_custom.intreq = IF_AUD2; |
|
generic_handle_irq(IRQ_AMIGA_AUD2); |
|
} |
|
|
|
/* if audio 3 interrupt */ |
|
if (ints & IF_AUD3) { |
|
amiga_custom.intreq = IF_AUD3; |
|
generic_handle_irq(IRQ_AMIGA_AUD3); |
|
} |
|
} |
|
|
|
static void ami_int5(struct irq_desc *desc) |
|
{ |
|
unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
|
|
|
/* if serial receive buffer full interrupt */ |
|
if (ints & IF_RBF) { |
|
/* acknowledge of IF_RBF must be done by the serial interrupt */ |
|
generic_handle_irq(IRQ_AMIGA_RBF); |
|
} |
|
|
|
/* if a disk sync interrupt */ |
|
if (ints & IF_DSKSYN) { |
|
amiga_custom.intreq = IF_DSKSYN; |
|
generic_handle_irq(IRQ_AMIGA_DSKSYN); |
|
} |
|
} |
|
|
|
|
|
/* |
|
* void amiga_init_IRQ(void) |
|
* |
|
* Parameters: None |
|
* |
|
* Returns: Nothing |
|
* |
|
* This function should be called during kernel startup to initialize |
|
* the amiga IRQ handling routines. |
|
*/ |
|
|
|
void __init amiga_init_IRQ(void) |
|
{ |
|
m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER, |
|
AMI_STD_IRQS); |
|
|
|
irq_set_chained_handler(IRQ_AUTO_1, ami_int1); |
|
irq_set_chained_handler(IRQ_AUTO_3, ami_int3); |
|
irq_set_chained_handler(IRQ_AUTO_4, ami_int4); |
|
irq_set_chained_handler(IRQ_AUTO_5, ami_int5); |
|
|
|
/* turn off PCMCIA interrupts */ |
|
if (AMIGAHW_PRESENT(PCMCIA)) |
|
gayle.inten = GAYLE_IRQ_IDE; |
|
|
|
/* turn off all interrupts and enable the master interrupt bit */ |
|
amiga_custom.intena = 0x7fff; |
|
amiga_custom.intreq = 0x7fff; |
|
amiga_custom.intena = IF_SETCLR | IF_INTEN; |
|
|
|
cia_init_IRQ(&ciaa_base); |
|
cia_init_IRQ(&ciab_base); |
|
}
|
|
|