/*1* linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code2*3* This file is subject to the terms and conditions of the GNU General Public4* License. See the file COPYING in the main directory of this archive5* for more details.6*7* 11/07/96: rewritten interrupt handling, irq lists are exists now only for8* this sources where it makes sense (VERTB/PORTS/EXTER) and you must9* be careful that dev_id for this sources is unique since this the10* only possibility to distinguish between different handlers for11* free_irq. irq lists also have different irq flags:12* - IRQ_FLG_FAST: handler is inserted at top of list (after other13* fast handlers)14* - IRQ_FLG_SLOW: handler is inserted at bottom of list and before15* they're executed irq level is set to the previous16* one, but handlers don't need to be reentrant, if17* reentrance occurred, slow handlers will be just18* called again.19* The whole interrupt handling for CIAs is moved to cia.c20* /Roman Zippel21*22* 07/08/99: rewamp of the interrupt handling - we now have two types of23* interrupts, normal and fast handlers, fast handlers being24* marked with IRQF_DISABLED and runs with all other interrupts25* disabled. Normal interrupts disable their own source but26* run with all other interrupt sources enabled.27* PORTS and EXTER interrupts are always shared even if the28* drivers do not explicitly mark this when calling29* request_irq which they really should do.30* This is similar to the way interrupts are handled on all31* other architectures and makes a ton of sense besides32* having the advantage of making it easier to share33* drivers.34* /Jes35*/3637#include <linux/init.h>38#include <linux/interrupt.h>39#include <linux/errno.h>4041#include <asm/irq.h>42#include <asm/traps.h>43#include <asm/amigahw.h>44#include <asm/amigaints.h>45#include <asm/amipcmcia.h>4647static void amiga_enable_irq(unsigned int irq);48static void amiga_disable_irq(unsigned int irq);49static irqreturn_t ami_int1(int irq, void *dev_id);50static irqreturn_t ami_int3(int irq, void *dev_id);51static irqreturn_t ami_int4(int irq, void *dev_id);52static irqreturn_t ami_int5(int irq, void *dev_id);5354static struct irq_controller amiga_irq_controller = {55.name = "amiga",56.lock = __SPIN_LOCK_UNLOCKED(amiga_irq_controller.lock),57.enable = amiga_enable_irq,58.disable = amiga_disable_irq,59};6061/*62* void amiga_init_IRQ(void)63*64* Parameters: None65*66* Returns: Nothing67*68* This function should be called during kernel startup to initialize69* the amiga IRQ handling routines.70*/7172void __init amiga_init_IRQ(void)73{74if (request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL))75pr_err("Couldn't register int%d\n", 1);76if (request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL))77pr_err("Couldn't register int%d\n", 3);78if (request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL))79pr_err("Couldn't register int%d\n", 4);80if (request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL))81pr_err("Couldn't register int%d\n", 5);8283m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS);8485/* turn off PCMCIA interrupts */86if (AMIGAHW_PRESENT(PCMCIA))87gayle.inten = GAYLE_IRQ_IDE;8889/* turn off all interrupts and enable the master interrupt bit */90amiga_custom.intena = 0x7fff;91amiga_custom.intreq = 0x7fff;92amiga_custom.intena = IF_SETCLR | IF_INTEN;9394cia_init_IRQ(&ciaa_base);95cia_init_IRQ(&ciab_base);96}9798/*99* Enable/disable a particular machine specific interrupt source.100* Note that this may affect other interrupts in case of a shared interrupt.101* This function should only be called for a _very_ short time to change some102* internal data, that may not be changed by the interrupt at the same time.103*/104105static void amiga_enable_irq(unsigned int irq)106{107amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER));108}109110static void amiga_disable_irq(unsigned int irq)111{112amiga_custom.intena = 1 << (irq - IRQ_USER);113}114115/*116* The builtin Amiga hardware interrupt handlers.117*/118119static irqreturn_t ami_int1(int irq, void *dev_id)120{121unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;122123/* if serial transmit buffer empty, interrupt */124if (ints & IF_TBE) {125amiga_custom.intreq = IF_TBE;126m68k_handle_int(IRQ_AMIGA_TBE);127}128129/* if floppy disk transfer complete, interrupt */130if (ints & IF_DSKBLK) {131amiga_custom.intreq = IF_DSKBLK;132m68k_handle_int(IRQ_AMIGA_DSKBLK);133}134135/* if software interrupt set, interrupt */136if (ints & IF_SOFT) {137amiga_custom.intreq = IF_SOFT;138m68k_handle_int(IRQ_AMIGA_SOFT);139}140return IRQ_HANDLED;141}142143static irqreturn_t ami_int3(int irq, void *dev_id)144{145unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;146147/* if a blitter interrupt */148if (ints & IF_BLIT) {149amiga_custom.intreq = IF_BLIT;150m68k_handle_int(IRQ_AMIGA_BLIT);151}152153/* if a copper interrupt */154if (ints & IF_COPER) {155amiga_custom.intreq = IF_COPER;156m68k_handle_int(IRQ_AMIGA_COPPER);157}158159/* if a vertical blank interrupt */160if (ints & IF_VERTB) {161amiga_custom.intreq = IF_VERTB;162m68k_handle_int(IRQ_AMIGA_VERTB);163}164return IRQ_HANDLED;165}166167static irqreturn_t ami_int4(int irq, void *dev_id)168{169unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;170171/* if audio 0 interrupt */172if (ints & IF_AUD0) {173amiga_custom.intreq = IF_AUD0;174m68k_handle_int(IRQ_AMIGA_AUD0);175}176177/* if audio 1 interrupt */178if (ints & IF_AUD1) {179amiga_custom.intreq = IF_AUD1;180m68k_handle_int(IRQ_AMIGA_AUD1);181}182183/* if audio 2 interrupt */184if (ints & IF_AUD2) {185amiga_custom.intreq = IF_AUD2;186m68k_handle_int(IRQ_AMIGA_AUD2);187}188189/* if audio 3 interrupt */190if (ints & IF_AUD3) {191amiga_custom.intreq = IF_AUD3;192m68k_handle_int(IRQ_AMIGA_AUD3);193}194return IRQ_HANDLED;195}196197static irqreturn_t ami_int5(int irq, void *dev_id)198{199unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;200201/* if serial receive buffer full interrupt */202if (ints & IF_RBF) {203/* acknowledge of IF_RBF must be done by the serial interrupt */204m68k_handle_int(IRQ_AMIGA_RBF);205}206207/* if a disk sync interrupt */208if (ints & IF_DSKSYN) {209amiga_custom.intreq = IF_DSKSYN;210m68k_handle_int(IRQ_AMIGA_DSKSYN);211}212return IRQ_HANDLED;213}214215216