2005-04-16 15:20:36 -07:00
/*
2011-05-31 11:11:01 +02:00
* Amiga Linux interrupt handling code
2005-04-16 15:20:36 -07:00
*
* 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>
2006-06-25 05:47:00 -07:00
# include <linux/interrupt.h>
2005-04-16 15:20:36 -07:00
# include <linux/errno.h>
2011-05-31 22:08:28 +02:00
# include <linux/irq.h>
2005-04-16 15:20:36 -07:00
# 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 .
*/
2011-04-17 22:53:04 +02:00
static void amiga_irq_enable ( struct irq_data * data )
2005-04-16 15:20:36 -07:00
{
2011-04-17 22:53:04 +02:00
amiga_custom . intena = IF_SETCLR | ( 1 < < ( data - > irq - IRQ_USER ) ) ;
2005-04-16 15:20:36 -07:00
}
2011-04-17 22:53:04 +02:00
static void amiga_irq_disable ( struct irq_data * data )
2005-04-16 15:20:36 -07:00
{
2011-04-17 22:53:04 +02:00
amiga_custom . intena = 1 < < ( data - > irq - IRQ_USER ) ;
2005-04-16 15:20:36 -07:00
}
2011-05-31 11:11:01 +02:00
static struct irq_chip amiga_irq_chip = {
. name = " amiga " ,
. irq_enable = amiga_irq_enable ,
. irq_disable = amiga_irq_disable ,
} ;
2005-04-16 15:20:36 -07:00
/*
* The builtin Amiga hardware interrupt handlers .
*/
2011-06-01 11:49:18 +02:00
static void ami_int1 ( unsigned int irq , 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 ( unsigned int irq , 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 ( unsigned int irq , 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 ( unsigned int irq , 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 ) ;
}
}
2011-05-31 11:11:01 +02:00
/*
* 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 )
{
2011-06-01 11:49:18 +02:00
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 ) ;
2011-05-31 11:11:01 +02:00
/* 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 ) ;
}