root/arch/m68k/amiga/cia.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cia_set_irq
  2. cia_able_irq
  3. cia_handler
  4. cia_irq_enable
  5. cia_irq_disable
  6. auto_irq_enable
  7. auto_irq_disable
  8. cia_init_IRQ

   1 /*
   2  *  linux/arch/m68k/amiga/cia.c - CIA support
   3  *
   4  *  Copyright (C) 1996 Roman Zippel
   5  *
   6  *  The concept of some functions bases on the original Amiga OS function
   7  *
   8  * This file is subject to the terms and conditions of the GNU General Public
   9  * License.  See the file COPYING in the main directory of this archive
  10  * for more details.
  11  */
  12 
  13 #include <linux/types.h>
  14 #include <linux/kernel.h>
  15 #include <linux/sched.h>
  16 #include <linux/errno.h>
  17 #include <linux/kernel_stat.h>
  18 #include <linux/init.h>
  19 #include <linux/seq_file.h>
  20 #include <linux/interrupt.h>
  21 #include <linux/irq.h>
  22 
  23 #include <asm/irq.h>
  24 #include <asm/amigahw.h>
  25 #include <asm/amigaints.h>
  26 
  27 struct ciabase {
  28         volatile struct CIA *cia;
  29         unsigned char icr_mask, icr_data;
  30         unsigned short int_mask;
  31         int handler_irq, cia_irq, server_irq;
  32         char *name;
  33 } ciaa_base = {
  34         .cia            = &ciaa,
  35         .int_mask       = IF_PORTS,
  36         .handler_irq    = IRQ_AMIGA_PORTS,
  37         .cia_irq        = IRQ_AMIGA_CIAA,
  38         .name           = "CIAA"
  39 }, ciab_base = {
  40         .cia            = &ciab,
  41         .int_mask       = IF_EXTER,
  42         .handler_irq    = IRQ_AMIGA_EXTER,
  43         .cia_irq        = IRQ_AMIGA_CIAB,
  44         .name           = "CIAB"
  45 };
  46 
  47 /*
  48  *  Cause or clear CIA interrupts, return old interrupt status.
  49  */
  50 
  51 unsigned char cia_set_irq(struct ciabase *base, unsigned char mask)
  52 {
  53         unsigned char old;
  54 
  55         old = (base->icr_data |= base->cia->icr);
  56         if (mask & CIA_ICR_SETCLR)
  57                 base->icr_data |= mask;
  58         else
  59                 base->icr_data &= ~mask;
  60         if (base->icr_data & base->icr_mask)
  61                 amiga_custom.intreq = IF_SETCLR | base->int_mask;
  62         return old & base->icr_mask;
  63 }
  64 
  65 /*
  66  *  Enable or disable CIA interrupts, return old interrupt mask,
  67  */
  68 
  69 unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
  70 {
  71         unsigned char old;
  72 
  73         old = base->icr_mask;
  74         base->icr_data |= base->cia->icr;
  75         base->cia->icr = mask;
  76         if (mask & CIA_ICR_SETCLR)
  77                 base->icr_mask |= mask;
  78         else
  79                 base->icr_mask &= ~mask;
  80         base->icr_mask &= CIA_ICR_ALL;
  81         if (base->icr_data & base->icr_mask)
  82                 amiga_custom.intreq = IF_SETCLR | base->int_mask;
  83         return old;
  84 }
  85 
  86 static irqreturn_t cia_handler(int irq, void *dev_id)
  87 {
  88         struct ciabase *base = dev_id;
  89         int mach_irq;
  90         unsigned char ints;
  91         unsigned long flags;
  92 
  93         /* Interrupts get disabled while the timer irq flag is cleared and
  94          * the timer interrupt serviced.
  95          */
  96         mach_irq = base->cia_irq;
  97         local_irq_save(flags);
  98         ints = cia_set_irq(base, CIA_ICR_ALL);
  99         amiga_custom.intreq = base->int_mask;
 100         if (ints & 1)
 101                 generic_handle_irq(mach_irq);
 102         local_irq_restore(flags);
 103         mach_irq++, ints >>= 1;
 104         for (; ints; mach_irq++, ints >>= 1) {
 105                 if (ints & 1)
 106                         generic_handle_irq(mach_irq);
 107         }
 108         return IRQ_HANDLED;
 109 }
 110 
 111 static void cia_irq_enable(struct irq_data *data)
 112 {
 113         unsigned int irq = data->irq;
 114         unsigned char mask;
 115 
 116         if (irq >= IRQ_AMIGA_CIAB) {
 117                 mask = 1 << (irq - IRQ_AMIGA_CIAB);
 118                 cia_set_irq(&ciab_base, mask);
 119                 cia_able_irq(&ciab_base, CIA_ICR_SETCLR | mask);
 120         } else {
 121                 mask = 1 << (irq - IRQ_AMIGA_CIAA);
 122                 cia_set_irq(&ciaa_base, mask);
 123                 cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask);
 124         }
 125 }
 126 
 127 static void cia_irq_disable(struct irq_data *data)
 128 {
 129         unsigned int irq = data->irq;
 130 
 131         if (irq >= IRQ_AMIGA_CIAB)
 132                 cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
 133         else
 134                 cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
 135 }
 136 
 137 static struct irq_chip cia_irq_chip = {
 138         .name           = "cia",
 139         .irq_enable     = cia_irq_enable,
 140         .irq_disable    = cia_irq_disable,
 141 };
 142 
 143 /*
 144  * Override auto irq 2 & 6 and use them as general chain
 145  * for external interrupts, we link the CIA interrupt sources
 146  * into this chain.
 147  */
 148 
 149 static void auto_irq_enable(struct irq_data *data)
 150 {
 151         switch (data->irq) {
 152         case IRQ_AUTO_2:
 153                 amiga_custom.intena = IF_SETCLR | IF_PORTS;
 154                 break;
 155         case IRQ_AUTO_6:
 156                 amiga_custom.intena = IF_SETCLR | IF_EXTER;
 157                 break;
 158         }
 159 }
 160 
 161 static void auto_irq_disable(struct irq_data *data)
 162 {
 163         switch (data->irq) {
 164         case IRQ_AUTO_2:
 165                 amiga_custom.intena = IF_PORTS;
 166                 break;
 167         case IRQ_AUTO_6:
 168                 amiga_custom.intena = IF_EXTER;
 169                 break;
 170         }
 171 }
 172 
 173 static struct irq_chip auto_irq_chip = {
 174         .name           = "auto",
 175         .irq_enable     = auto_irq_enable,
 176         .irq_disable    = auto_irq_disable,
 177 };
 178 
 179 void __init cia_init_IRQ(struct ciabase *base)
 180 {
 181         m68k_setup_irq_controller(&cia_irq_chip, handle_simple_irq,
 182                                   base->cia_irq, CIA_IRQS);
 183 
 184         /* clear any pending interrupt and turn off all interrupts */
 185         cia_set_irq(base, CIA_ICR_ALL);
 186         cia_able_irq(base, CIA_ICR_ALL);
 187 
 188         /* override auto int and install CIA handler */
 189         m68k_setup_irq_controller(&auto_irq_chip, handle_simple_irq,
 190                                   base->handler_irq, 1);
 191         m68k_irq_startup_irq(base->handler_irq);
 192         if (request_irq(base->handler_irq, cia_handler, IRQF_SHARED,
 193                         base->name, base))
 194                 pr_err("Couldn't register %s interrupt\n", base->name);
 195 }

/* [<][>][^][v][top][bottom][index][help] */