linux-old/arch/ppc/amiga/cia.c
<<
>>
Prefs
   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/interrupt.h>
  17#include <linux/irq.h>
  18#include <linux/kernel_stat.h>
  19#include <linux/init.h>
  20
  21#include <asm/irq.h>
  22#include <asm/amigahw.h>
  23#include <asm/amigaints.h>
  24
  25struct ciabase {
  26        volatile struct CIA *cia;
  27        u_char icr_mask, icr_data;
  28        u_short int_mask;
  29        int handler_irq, cia_irq, server_irq;
  30        char *name;
  31} ciaa_base = {
  32        &ciaa, 0, 0, IF_PORTS,
  33        IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
  34        IRQ_AMIGA_PORTS,
  35        "CIAA handler"
  36}, ciab_base = {
  37        &ciab, 0, 0, IF_EXTER,
  38        IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB,
  39        IRQ_AMIGA_EXTER,
  40        "CIAB handler"
  41};
  42
  43#define CIA_SET_BASE_ADJUST_IRQ(base, irq)      \
  44do {                                            \
  45        if (irq >= IRQ_AMIGA_CIAB) {            \
  46                base = &ciab_base;              \
  47                irq -= IRQ_AMIGA_CIAB;          \
  48        } else {                                \
  49                base = &ciaa_base;              \
  50                irq -= IRQ_AMIGA_CIAA;          \
  51        }                                       \
  52} while (0)
  53
  54/*
  55 *  Cause or clear CIA interrupts, return old interrupt status.
  56 */
  57
  58static unsigned char cia_set_irq_private(struct ciabase *base,
  59                                         unsigned char mask)
  60{
  61        u_char old;
  62
  63        old = (base->icr_data |= base->cia->icr);
  64        if (mask & CIA_ICR_SETCLR)
  65                base->icr_data |= mask;
  66        else
  67                base->icr_data &= ~mask;
  68        if (base->icr_data & base->icr_mask)
  69                custom.intreq = IF_SETCLR | base->int_mask;
  70        return old & base->icr_mask;
  71}
  72
  73unsigned char cia_set_irq(unsigned int irq, int set)
  74{
  75        struct ciabase *base;
  76        unsigned char mask;
  77
  78        if (irq >= IRQ_AMIGA_CIAB)
  79                mask = (1 << (irq - IRQ_AMIGA_CIAB));
  80        else
  81                mask = (1 << (irq - IRQ_AMIGA_CIAA));
  82        mask |= (set) ? CIA_ICR_SETCLR : 0;
  83
  84        CIA_SET_BASE_ADJUST_IRQ(base, irq);
  85
  86        return cia_set_irq_private(base, mask);
  87}
  88
  89unsigned char cia_get_irq_mask(unsigned int irq)
  90{
  91        struct ciabase *base;
  92
  93        CIA_SET_BASE_ADJUST_IRQ(base, irq);
  94
  95        return base->cia->icr;
  96}
  97
  98/*
  99 *  Enable or disable CIA interrupts, return old interrupt mask.
 100 */
 101
 102static unsigned char cia_able_irq_private(struct ciabase *base,
 103                                          unsigned char mask)
 104{
 105        u_char old;
 106
 107        old = base->icr_mask;
 108        base->icr_data |= base->cia->icr;
 109        base->cia->icr = mask;
 110        if (mask & CIA_ICR_SETCLR)
 111                base->icr_mask |= mask;
 112        else
 113                base->icr_mask &= ~mask;
 114        base->icr_mask &= CIA_ICR_ALL;
 115
 116        if (base->icr_data & base->icr_mask)
 117                custom.intreq = IF_SETCLR | base->int_mask;
 118        return old;
 119}
 120
 121unsigned char cia_able_irq(unsigned int irq, int enable)
 122{
 123        struct ciabase *base;
 124        unsigned char mask;
 125
 126        if (irq >= IRQ_AMIGA_CIAB)
 127                mask = (1 << (irq - IRQ_AMIGA_CIAB));
 128        else
 129                mask = (1 << (irq - IRQ_AMIGA_CIAA));
 130        mask |= (enable) ? CIA_ICR_SETCLR : 0;
 131
 132        CIA_SET_BASE_ADJUST_IRQ(base, irq);
 133
 134        return cia_able_irq_private(base, mask);
 135}
 136
 137static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
 138{
 139        struct ciabase *base = (struct ciabase *)dev_id;
 140        irq_desc_t *desc;
 141        struct irqaction *action;
 142        int i;
 143        unsigned char ints;
 144
 145        irq = base->cia_irq;
 146        desc = irq_desc + irq;
 147        ints = cia_set_irq_private(base, CIA_ICR_ALL);
 148        custom.intreq = base->int_mask;
 149        for (i = 0; i < CIA_IRQS; i++, irq++) {
 150                if (ints & 1) {
 151                        kstat.irqs[0][irq]++;
 152                        action = desc->action;
 153                        action->handler(irq, action->dev_id, fp);
 154                }
 155                ints >>= 1;
 156                desc++;
 157        }
 158        amiga_do_irq_list(base->server_irq, fp);
 159}
 160
 161void __init cia_init_IRQ(struct ciabase *base)
 162{
 163        extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
 164        struct irqaction *action;
 165
 166        /* clear any pending interrupt and turn off all interrupts */
 167        cia_set_irq_private(base, CIA_ICR_ALL);
 168        cia_able_irq_private(base, CIA_ICR_ALL);
 169
 170        /* install CIA handler */
 171        action = &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO];
 172        action->handler = cia_handler;
 173        action->dev_id = base;
 174        action->name = base->name;
 175        setup_irq(base->handler_irq, &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO]);
 176
 177        custom.intena = IF_SETCLR | base->int_mask;
 178}
 179
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.