linux/arch/m68k/amiga/amiints.c
<<
>>
Prefs
   1/*
   2 * Amiga Linux interrupt handling code
   3 *
   4 * This file is subject to the terms and conditions of the GNU General Public
   5 * License.  See the file COPYING in the main directory of this archive
   6 * for more details.
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/interrupt.h>
  11#include <linux/errno.h>
  12#include <linux/irq.h>
  13
  14#include <asm/irq.h>
  15#include <asm/traps.h>
  16#include <asm/amigahw.h>
  17#include <asm/amigaints.h>
  18#include <asm/amipcmcia.h>
  19
  20
  21/*
  22 * Enable/disable a particular machine specific interrupt source.
  23 * Note that this may affect other interrupts in case of a shared interrupt.
  24 * This function should only be called for a _very_ short time to change some
  25 * internal data, that may not be changed by the interrupt at the same time.
  26 */
  27
  28static void amiga_irq_enable(struct irq_data *data)
  29{
  30        amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER));
  31}
  32
  33static void amiga_irq_disable(struct irq_data *data)
  34{
  35        amiga_custom.intena = 1 << (data->irq - IRQ_USER);
  36}
  37
  38static struct irq_chip amiga_irq_chip = {
  39        .name           = "amiga",
  40        .irq_enable     = amiga_irq_enable,
  41        .irq_disable    = amiga_irq_disable,
  42};
  43
  44
  45/*
  46 * The builtin Amiga hardware interrupt handlers.
  47 */
  48
  49static void ami_int1(struct irq_desc *desc)
  50{
  51        unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  52
  53        /* if serial transmit buffer empty, interrupt */
  54        if (ints & IF_TBE) {
  55                amiga_custom.intreq = IF_TBE;
  56                generic_handle_irq(IRQ_AMIGA_TBE);
  57        }
  58
  59        /* if floppy disk transfer complete, interrupt */
  60        if (ints & IF_DSKBLK) {
  61                amiga_custom.intreq = IF_DSKBLK;
  62                generic_handle_irq(IRQ_AMIGA_DSKBLK);
  63        }
  64
  65        /* if software interrupt set, interrupt */
  66        if (ints & IF_SOFT) {
  67                amiga_custom.intreq = IF_SOFT;
  68                generic_handle_irq(IRQ_AMIGA_SOFT);
  69        }
  70}
  71
  72static void ami_int3(struct irq_desc *desc)
  73{
  74        unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  75
  76        /* if a blitter interrupt */
  77        if (ints & IF_BLIT) {
  78                amiga_custom.intreq = IF_BLIT;
  79                generic_handle_irq(IRQ_AMIGA_BLIT);
  80        }
  81
  82        /* if a copper interrupt */
  83        if (ints & IF_COPER) {
  84                amiga_custom.intreq = IF_COPER;
  85                generic_handle_irq(IRQ_AMIGA_COPPER);
  86        }
  87
  88        /* if a vertical blank interrupt */
  89        if (ints & IF_VERTB) {
  90                amiga_custom.intreq = IF_VERTB;
  91                generic_handle_irq(IRQ_AMIGA_VERTB);
  92        }
  93}
  94
  95static void ami_int4(struct irq_desc *desc)
  96{
  97        unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  98
  99        /* if audio 0 interrupt */
 100        if (ints & IF_AUD0) {
 101                amiga_custom.intreq = IF_AUD0;
 102                generic_handle_irq(IRQ_AMIGA_AUD0);
 103        }
 104
 105        /* if audio 1 interrupt */
 106        if (ints & IF_AUD1) {
 107                amiga_custom.intreq = IF_AUD1;
 108                generic_handle_irq(IRQ_AMIGA_AUD1);
 109        }
 110
 111        /* if audio 2 interrupt */
 112        if (ints & IF_AUD2) {
 113                amiga_custom.intreq = IF_AUD2;
 114                generic_handle_irq(IRQ_AMIGA_AUD2);
 115        }
 116
 117        /* if audio 3 interrupt */
 118        if (ints & IF_AUD3) {
 119                amiga_custom.intreq = IF_AUD3;
 120                generic_handle_irq(IRQ_AMIGA_AUD3);
 121        }
 122}
 123
 124static void ami_int5(struct irq_desc *desc)
 125{
 126        unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
 127
 128        /* if serial receive buffer full interrupt */
 129        if (ints & IF_RBF) {
 130                /* acknowledge of IF_RBF must be done by the serial interrupt */
 131                generic_handle_irq(IRQ_AMIGA_RBF);
 132        }
 133
 134        /* if a disk sync interrupt */
 135        if (ints & IF_DSKSYN) {
 136                amiga_custom.intreq = IF_DSKSYN;
 137                generic_handle_irq(IRQ_AMIGA_DSKSYN);
 138        }
 139}
 140
 141
 142/*
 143 * void amiga_init_IRQ(void)
 144 *
 145 * Parameters:  None
 146 *
 147 * Returns:     Nothing
 148 *
 149 * This function should be called during kernel startup to initialize
 150 * the amiga IRQ handling routines.
 151 */
 152
 153void __init amiga_init_IRQ(void)
 154{
 155        m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
 156                                  AMI_STD_IRQS);
 157
 158        irq_set_chained_handler(IRQ_AUTO_1, ami_int1);
 159        irq_set_chained_handler(IRQ_AUTO_3, ami_int3);
 160        irq_set_chained_handler(IRQ_AUTO_4, ami_int4);
 161        irq_set_chained_handler(IRQ_AUTO_5, ami_int5);
 162
 163        /* turn off PCMCIA interrupts */
 164        if (AMIGAHW_PRESENT(PCMCIA))
 165                gayle.inten = GAYLE_IRQ_IDE;
 166
 167        /* turn off all interrupts and enable the master interrupt bit */
 168        amiga_custom.intena = 0x7fff;
 169        amiga_custom.intreq = 0x7fff;
 170        amiga_custom.intena = IF_SETCLR | IF_INTEN;
 171
 172        cia_init_IRQ(&ciaa_base);
 173        cia_init_IRQ(&ciab_base);
 174}
 175