2 * linux/arch/m68k/amiga/cia.c - CIA support
4 * Copyright (C) 1996 Roman Zippel
6 * The concept of some functions bases on the original Amiga OS function
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
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>
21 #include <asm/amigahw.h>
22 #include <asm/amigaints.h>
25 volatile struct CIA *cia;
26 u_char icr_mask, icr_data;
28 int handler_irq, cia_irq, server_irq;
30 struct irq_server server;
31 irq_handler_t irq_list[CIA_IRQS];
33 &ciaa, 0, 0, IF_PORTS,
34 IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
36 "CIAA handler", {0, 0}
38 &ciab, 0, 0, IF_EXTER,
39 IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB,
41 "CIAB handler", {0, 0}
44 #define CIA_SET_BASE_ADJUST_IRQ(base, irq) \
46 if (irq >= IRQ_AMIGA_CIAB) { \
48 irq -= IRQ_AMIGA_CIAB; \
51 irq -= IRQ_AMIGA_CIAA; \
56 * Cause or clear CIA interrupts, return old interrupt status.
59 static unsigned char cia_set_irq_private(struct ciabase *base,
64 old = (base->icr_data |= base->cia->icr);
65 if (mask & CIA_ICR_SETCLR)
66 base->icr_data |= mask;
68 base->icr_data &= ~mask;
69 if (base->icr_data & base->icr_mask)
70 custom.intreq = IF_SETCLR | base->int_mask;
71 return old & base->icr_mask;
74 unsigned char cia_set_irq(unsigned int irq, int set)
79 if (irq >= IRQ_AMIGA_CIAB)
80 mask = (1 << (irq - IRQ_AMIGA_CIAB));
82 mask = (1 << (irq - IRQ_AMIGA_CIAA));
83 mask |= (set) ? CIA_ICR_SETCLR : 0;
85 CIA_SET_BASE_ADJUST_IRQ(base, irq);
87 return cia_set_irq_private(base, mask);
90 unsigned char cia_get_irq_mask(unsigned int irq)
94 CIA_SET_BASE_ADJUST_IRQ(base, irq);
96 return base->cia->icr;
100 * Enable or disable CIA interrupts, return old interrupt mask,
101 * interrupts will only be enabled if a handler exists
104 static unsigned char cia_able_irq_private(struct ciabase *base,
110 old = base->icr_mask;
111 base->icr_data |= base->cia->icr;
112 base->cia->icr = mask;
113 if (mask & CIA_ICR_SETCLR)
114 base->icr_mask |= mask;
116 base->icr_mask &= ~mask;
117 base->icr_mask &= CIA_ICR_ALL;
118 for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
119 if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
120 base->icr_mask &= ~tmp;
121 base->cia->icr = tmp;
124 if (base->icr_data & base->icr_mask)
125 custom.intreq = IF_SETCLR | base->int_mask;
129 unsigned char cia_able_irq(unsigned int irq, int enable)
131 struct ciabase *base;
134 if (irq >= IRQ_AMIGA_CIAB)
135 mask = (1 << (irq - IRQ_AMIGA_CIAB));
137 mask = (1 << (irq - IRQ_AMIGA_CIAA));
138 mask |= (enable) ? CIA_ICR_SETCLR : 0;
140 CIA_SET_BASE_ADJUST_IRQ(base, irq);
142 return cia_able_irq_private(base, mask);
145 int cia_request_irq(unsigned int irq,
146 void (*handler)(int, void *, struct pt_regs *),
147 unsigned long flags, const char *devname, void *dev_id)
150 struct ciabase *base;
152 CIA_SET_BASE_ADJUST_IRQ(base, irq);
154 base->irq_list[irq].handler = handler;
155 base->irq_list[irq].flags = flags;
156 base->irq_list[irq].dev_id = dev_id;
157 base->irq_list[irq].devname = devname;
159 /* enable the interrupt */
161 cia_set_irq_private(base, mask);
162 cia_able_irq_private(base, CIA_ICR_SETCLR | mask);
166 void cia_free_irq(unsigned int irq, void *dev_id)
168 struct ciabase *base;
170 CIA_SET_BASE_ADJUST_IRQ(base, irq);
172 if (base->irq_list[irq].dev_id != dev_id)
173 printk("%s: removing probably wrong IRQ %i from %s\n",
174 __FUNCTION__, base->cia_irq + irq,
175 base->irq_list[irq].devname);
177 base->irq_list[irq].handler = NULL;
178 base->irq_list[irq].flags = 0;
180 cia_able_irq_private(base, 1 << irq);
183 static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
185 struct ciabase *base = (struct ciabase *)dev_id;
189 mach_irq = base->cia_irq;
190 irq = SYS_IRQS + mach_irq;
191 ints = cia_set_irq_private(base, CIA_ICR_ALL);
192 custom.intreq = base->int_mask;
193 for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
195 kstat.irqs[0][irq]++;
196 base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
200 amiga_do_irq_list(base->server_irq, fp, &base->server);
203 void __init cia_init_IRQ(struct ciabase *base)
207 /* init isr handlers */
208 for (i = 0; i < CIA_IRQS; i++) {
209 base->irq_list[i].handler = NULL;
210 base->irq_list[i].flags = 0;
213 /* clear any pending interrupt and turn off all interrupts */
214 cia_set_irq_private(base, CIA_ICR_ALL);
215 cia_able_irq_private(base, CIA_ICR_ALL);
217 /* install CIA handler */
218 request_irq(base->handler_irq, cia_handler, 0, base->name, base);
220 custom.intena = IF_SETCLR | base->int_mask;
223 int cia_get_irq_list(struct ciabase *base, char *buf)
228 for (i = 0; i < CIA_IRQS; i++) {
229 len += sprintf(buf+len, "cia %2d: %10d ", j + i,
230 kstat.irqs[0][SYS_IRQS + j + i]);
231 len += sprintf(buf+len, " ");
232 len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);