175 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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);
 | |
| }
 |