2 * arch/ppc/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/interrupt.h>
17 #include <linux/irq.h>
18 #include <linux/kernel_stat.h>
19 #include <linux/init.h>
22 #include <asm/amigahw.h>
23 #include <asm/amigaints.h>
26 volatile struct CIA
*cia
;
27 u_char icr_mask
, icr_data
;
29 int handler_irq
, cia_irq
, server_irq
;
32 &ciaa
, 0, 0, IF_PORTS
,
33 IRQ_AMIGA_AUTO_2
, IRQ_AMIGA_CIAA
,
37 &ciab
, 0, 0, IF_EXTER
,
38 IRQ_AMIGA_AUTO_6
, IRQ_AMIGA_CIAB
,
43 #define CIA_SET_BASE_ADJUST_IRQ(base, irq) \
45 if (irq >= IRQ_AMIGA_CIAB) { \
47 irq -= IRQ_AMIGA_CIAB; \
50 irq -= IRQ_AMIGA_CIAA; \
55 * Cause or clear CIA interrupts, return old interrupt status.
58 static unsigned char cia_set_irq_private(struct ciabase
*base
,
63 old
= (base
->icr_data
|= base
->cia
->icr
);
64 if (mask
& CIA_ICR_SETCLR
)
65 base
->icr_data
|= mask
;
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
;
73 unsigned char cia_set_irq(unsigned int irq
, int set
)
78 if (irq
>= IRQ_AMIGA_CIAB
)
79 mask
= (1 << (irq
- IRQ_AMIGA_CIAB
));
81 mask
= (1 << (irq
- IRQ_AMIGA_CIAA
));
82 mask
|= (set
) ? CIA_ICR_SETCLR
: 0;
84 CIA_SET_BASE_ADJUST_IRQ(base
, irq
);
86 return cia_set_irq_private(base
, mask
);
89 unsigned char cia_get_irq_mask(unsigned int irq
)
93 CIA_SET_BASE_ADJUST_IRQ(base
, irq
);
95 return base
->cia
->icr
;
99 * Enable or disable CIA interrupts, return old interrupt mask.
102 static unsigned char cia_able_irq_private(struct ciabase
*base
,
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
;
113 base
->icr_mask
&= ~mask
;
114 base
->icr_mask
&= CIA_ICR_ALL
;
116 if (base
->icr_data
& base
->icr_mask
)
117 custom
.intreq
= IF_SETCLR
| base
->int_mask
;
121 unsigned char cia_able_irq(unsigned int irq
, int enable
)
123 struct ciabase
*base
;
126 if (irq
>= IRQ_AMIGA_CIAB
)
127 mask
= (1 << (irq
- IRQ_AMIGA_CIAB
));
129 mask
= (1 << (irq
- IRQ_AMIGA_CIAA
));
130 mask
|= (enable
) ? CIA_ICR_SETCLR
: 0;
132 CIA_SET_BASE_ADJUST_IRQ(base
, irq
);
134 return cia_able_irq_private(base
, mask
);
137 static void cia_handler(int irq
, void *dev_id
, struct pt_regs
*fp
)
139 struct ciabase
*base
= (struct ciabase
*)dev_id
;
141 struct irqaction
*action
;
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
++) {
151 kstat_cpu(0).irqs
[irq
]++;
152 action
= desc
->action
;
153 action
->handler(irq
, action
->dev_id
, fp
);
158 amiga_do_irq_list(base
->server_irq
, fp
);
161 void __init
cia_init_IRQ(struct ciabase
*base
)
163 extern struct irqaction amiga_sys_irqaction
[AUTO_IRQS
];
164 struct irqaction
*action
;
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
);
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
]);
177 custom
.intena
= IF_SETCLR
| base
->int_mask
;