2005-04-17 02:20:36 +04:00
/*
* linux / arch / m68k / amiga / amiints . 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 .
*
* 11 / 07 / 96 : rewritten interrupt handling , irq lists are exists now only for
* this sources where it makes sense ( VERTB / PORTS / EXTER ) and you must
* be careful that dev_id for this sources is unique since this the
* only possibility to distinguish between different handlers for
* free_irq . irq lists also have different irq flags :
* - IRQ_FLG_FAST : handler is inserted at top of list ( after other
* fast handlers )
* - IRQ_FLG_SLOW : handler is inserted at bottom of list and before
* they ' re executed irq level is set to the previous
* one , but handlers don ' t need to be reentrant , if
* reentrance occurred , slow handlers will be just
* called again .
* The whole interrupt handling for CIAs is moved to cia . c
* / Roman Zippel
*
* 07 / 08 / 99 : rewamp of the interrupt handling - we now have two types of
* interrupts , normal and fast handlers , fast handlers being
2006-07-02 06:29:19 +04:00
* marked with IRQF_DISABLED and runs with all other interrupts
2005-04-17 02:20:36 +04:00
* disabled . Normal interrupts disable their own source but
* run with all other interrupt sources enabled .
* PORTS and EXTER interrupts are always shared even if the
* drivers do not explicitly mark this when calling
* request_irq which they really should do .
* This is similar to the way interrupts are handled on all
* other architectures and makes a ton of sense besides
* having the advantage of making it easier to share
* drivers .
* / Jes
*/
# include <linux/init.h>
2006-06-25 16:47:00 +04:00
# include <linux/interrupt.h>
2005-04-17 02:20:36 +04:00
# include <linux/errno.h>
# include <asm/irq.h>
# include <asm/traps.h>
# include <asm/amigahw.h>
# include <asm/amigaints.h>
# include <asm/amipcmcia.h>
2006-06-25 16:47:01 +04:00
static void amiga_enable_irq ( unsigned int irq ) ;
static void amiga_disable_irq ( unsigned int irq ) ;
2006-10-07 17:16:45 +04:00
static irqreturn_t ami_int1 ( int irq , void * dev_id ) ;
static irqreturn_t ami_int3 ( int irq , void * dev_id ) ;
static irqreturn_t ami_int4 ( int irq , void * dev_id ) ;
static irqreturn_t ami_int5 ( int irq , void * dev_id ) ;
2006-06-25 16:47:01 +04:00
static struct irq_controller amiga_irq_controller = {
. name = " amiga " ,
2007-05-07 01:50:54 +04:00
. lock = __SPIN_LOCK_UNLOCKED ( amiga_irq_controller . lock ) ,
2006-06-25 16:47:01 +04:00
. enable = amiga_enable_irq ,
. disable = amiga_disable_irq ,
2005-04-17 02:20:36 +04: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 )
{
2006-06-25 16:47:01 +04:00
request_irq ( IRQ_AUTO_1 , ami_int1 , 0 , " int1 " , NULL ) ;
request_irq ( IRQ_AUTO_3 , ami_int3 , 0 , " int3 " , NULL ) ;
request_irq ( IRQ_AUTO_4 , ami_int4 , 0 , " int4 " , NULL ) ;
request_irq ( IRQ_AUTO_5 , ami_int5 , 0 , " int5 " , NULL ) ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:01 +04:00
m68k_setup_irq_controller ( & amiga_irq_controller , IRQ_USER , AMI_STD_IRQS ) ;
2005-04-17 02:20:36 +04:00
/* turn off PCMCIA interrupts */
if ( AMIGAHW_PRESENT ( PCMCIA ) )
gayle . inten = GAYLE_IRQ_IDE ;
/* turn off all interrupts and enable the master interrupt bit */
2006-01-12 12:06:12 +03:00
amiga_custom . intena = 0x7fff ;
amiga_custom . intreq = 0x7fff ;
amiga_custom . intena = IF_SETCLR | IF_INTEN ;
2005-04-17 02:20:36 +04:00
cia_init_IRQ ( & ciaa_base ) ;
cia_init_IRQ ( & ciab_base ) ;
}
/*
* 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 .
*/
2006-06-25 16:47:01 +04:00
static void amiga_enable_irq ( unsigned int irq )
2005-04-17 02:20:36 +04:00
{
2006-06-25 16:47:01 +04:00
amiga_custom . intena = IF_SETCLR | ( 1 < < ( irq - IRQ_USER ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-25 16:47:01 +04:00
static void amiga_disable_irq ( unsigned int irq )
2005-04-17 02:20:36 +04:00
{
2006-06-25 16:47:01 +04:00
amiga_custom . intena = 1 < < ( irq - IRQ_USER ) ;
2005-04-17 02:20:36 +04:00
}
/*
* The builtin Amiga hardware interrupt handlers .
*/
2006-10-07 17:16:45 +04:00
static irqreturn_t ami_int1 ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
2006-01-12 12:06:12 +03:00
unsigned short ints = amiga_custom . intreqr & amiga_custom . intenar ;
2005-04-17 02:20:36 +04:00
/* if serial transmit buffer empty, interrupt */
if ( ints & IF_TBE ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_TBE ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_TBE ) ;
2005-04-17 02:20:36 +04:00
}
/* if floppy disk transfer complete, interrupt */
if ( ints & IF_DSKBLK ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_DSKBLK ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_DSKBLK ) ;
2005-04-17 02:20:36 +04:00
}
/* if software interrupt set, interrupt */
if ( ints & IF_SOFT ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_SOFT ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_SOFT ) ;
2005-04-17 02:20:36 +04:00
}
return IRQ_HANDLED ;
}
2006-10-07 17:16:45 +04:00
static irqreturn_t ami_int3 ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
2006-01-12 12:06:12 +03:00
unsigned short ints = amiga_custom . intreqr & amiga_custom . intenar ;
2005-04-17 02:20:36 +04:00
/* if a blitter interrupt */
if ( ints & IF_BLIT ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_BLIT ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_BLIT ) ;
2005-04-17 02:20:36 +04:00
}
/* if a copper interrupt */
if ( ints & IF_COPER ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_COPER ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_COPPER ) ;
2005-04-17 02:20:36 +04:00
}
/* if a vertical blank interrupt */
2006-06-25 16:47:01 +04:00
if ( ints & IF_VERTB ) {
amiga_custom . intreq = IF_VERTB ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_VERTB ) ;
2006-06-25 16:47:01 +04:00
}
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
2006-10-07 17:16:45 +04:00
static irqreturn_t ami_int4 ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
2006-01-12 12:06:12 +03:00
unsigned short ints = amiga_custom . intreqr & amiga_custom . intenar ;
2005-04-17 02:20:36 +04:00
/* if audio 0 interrupt */
if ( ints & IF_AUD0 ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_AUD0 ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_AUD0 ) ;
2005-04-17 02:20:36 +04:00
}
/* if audio 1 interrupt */
if ( ints & IF_AUD1 ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_AUD1 ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_AUD1 ) ;
2005-04-17 02:20:36 +04:00
}
/* if audio 2 interrupt */
if ( ints & IF_AUD2 ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_AUD2 ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_AUD2 ) ;
2005-04-17 02:20:36 +04:00
}
/* if audio 3 interrupt */
if ( ints & IF_AUD3 ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_AUD3 ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_AUD3 ) ;
2005-04-17 02:20:36 +04:00
}
return IRQ_HANDLED ;
}
2006-10-07 17:16:45 +04:00
static irqreturn_t ami_int5 ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
2006-01-12 12:06:12 +03:00
unsigned short ints = amiga_custom . intreqr & amiga_custom . intenar ;
2005-04-17 02:20:36 +04:00
/* if serial receive buffer full interrupt */
if ( ints & IF_RBF ) {
/* acknowledge of IF_RBF must be done by the serial interrupt */
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_RBF ) ;
2005-04-17 02:20:36 +04:00
}
/* if a disk sync interrupt */
if ( ints & IF_DSKSYN ) {
2006-01-12 12:06:12 +03:00
amiga_custom . intreq = IF_DSKSYN ;
2006-10-07 17:16:45 +04:00
m68k_handle_int ( IRQ_AMIGA_DSKSYN ) ;
2005-04-17 02:20:36 +04:00
}
return IRQ_HANDLED ;
}