/*
|
/*
|
* amiints.c -- Amiga Linux interrupt handling code
|
* amiints.c -- Amiga Linux interrupt handling code
|
*
|
*
|
* This file is subject to the terms and conditions of the GNU General Public
|
* This file is subject to the terms and conditions of the GNU General Public
|
* License. See the file COPYING in the main directory of this archive
|
* License. See the file COPYING in the main directory of this archive
|
* for more details.
|
* for more details.
|
*
|
*
|
*/
|
*/
|
|
|
#include <linux/types.h>
|
#include <linux/types.h>
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
|
|
#include <asm/system.h>
|
#include <asm/system.h>
|
#include <asm/irq.h>
|
#include <asm/irq.h>
|
#include <asm/traps.h>
|
#include <asm/traps.h>
|
#include <asm/amigahw.h>
|
#include <asm/amigahw.h>
|
#include <asm/amigaints.h>
|
#include <asm/amigaints.h>
|
|
|
/* isr node variables for amiga interrupt sources */
|
/* isr node variables for amiga interrupt sources */
|
static isr_node_t *ami_lists[NUM_AMIGA_SOURCES];
|
static isr_node_t *ami_lists[NUM_AMIGA_SOURCES];
|
|
|
static const ushort ami_intena_vals[NUM_AMIGA_SOURCES] = {
|
static const ushort ami_intena_vals[NUM_AMIGA_SOURCES] = {
|
IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
|
IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
|
IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_PORTS, IF_PORTS, IF_PORTS,
|
IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_PORTS, IF_PORTS, IF_PORTS,
|
IF_PORTS, IF_PORTS, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER,
|
IF_PORTS, IF_PORTS, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER,
|
IF_SOFT, IF_PORTS, IF_EXTER
|
IF_SOFT, IF_PORTS, IF_EXTER
|
};
|
};
|
|
|
struct ciadata
|
struct ciadata
|
{
|
{
|
volatile struct CIA *ciaptr;
|
volatile struct CIA *ciaptr;
|
unsigned long baseirq;
|
unsigned long baseirq;
|
} ciadata[2];
|
} ciadata[2];
|
|
|
/*
|
/*
|
* index into ami_lists for IRQs. CIA IRQs are special, because
|
* index into ami_lists for IRQs. CIA IRQs are special, because
|
* the same cia interrupt handler is used for both CIAs.
|
* the same cia interrupt handler is used for both CIAs.
|
*/
|
*/
|
#define IRQ_IDX(source) (source & ~IRQ_MACHSPEC)
|
#define IRQ_IDX(source) (source & ~IRQ_MACHSPEC)
|
#define CIA_IRQ_IDX(source) (IRQ_IDX(datap->baseirq) \
|
#define CIA_IRQ_IDX(source) (IRQ_IDX(datap->baseirq) \
|
+(source-IRQ_AMIGA_CIAA_TA))
|
+(source-IRQ_AMIGA_CIAA_TA))
|
|
|
/*
|
/*
|
* void amiga_init_INTS (void)
|
* void amiga_init_INTS (void)
|
*
|
*
|
* Parameters: None
|
* Parameters: None
|
*
|
*
|
* Returns: Nothing
|
* Returns: Nothing
|
*
|
*
|
* This function should be called during kernel startup to initialize
|
* This function should be called during kernel startup to initialize
|
* the amiga IRQ handling routines.
|
* the amiga IRQ handling routines.
|
*/
|
*/
|
|
|
static void
|
static void
|
ami_int1(int irq, struct pt_regs *fp, void *data),
|
ami_int1(int irq, struct pt_regs *fp, void *data),
|
ami_int2(int irq, struct pt_regs *fp, void *data),
|
ami_int2(int irq, struct pt_regs *fp, void *data),
|
ami_int3(int irq, struct pt_regs *fp, void *data),
|
ami_int3(int irq, struct pt_regs *fp, void *data),
|
ami_int4(int irq, struct pt_regs *fp, void *data),
|
ami_int4(int irq, struct pt_regs *fp, void *data),
|
ami_int5(int irq, struct pt_regs *fp, void *data),
|
ami_int5(int irq, struct pt_regs *fp, void *data),
|
ami_int6(int irq, struct pt_regs *fp, void *data),
|
ami_int6(int irq, struct pt_regs *fp, void *data),
|
ami_int7(int irq, struct pt_regs *fp, void *data),
|
ami_int7(int irq, struct pt_regs *fp, void *data),
|
ami_intcia(int irq, struct pt_regs *fp, void *data);
|
ami_intcia(int irq, struct pt_regs *fp, void *data);
|
|
|
void amiga_init_INTS (void)
|
void amiga_init_INTS (void)
|
{
|
{
|
int i;
|
int i;
|
|
|
/* initialize handlers */
|
/* initialize handlers */
|
for (i = 0; i < NUM_AMIGA_SOURCES; i++)
|
for (i = 0; i < NUM_AMIGA_SOURCES; i++)
|
ami_lists[i] = NULL;
|
ami_lists[i] = NULL;
|
|
|
add_isr (IRQ1, ami_int1, 0, NULL, "int1 handler");
|
add_isr (IRQ1, ami_int1, 0, NULL, "int1 handler");
|
add_isr (IRQ2, ami_int2, 0, NULL, "int2 handler");
|
add_isr (IRQ2, ami_int2, 0, NULL, "int2 handler");
|
add_isr (IRQ3, ami_int3, 0, NULL, "int3 handler");
|
add_isr (IRQ3, ami_int3, 0, NULL, "int3 handler");
|
add_isr (IRQ4, ami_int4, 0, NULL, "int4 handler");
|
add_isr (IRQ4, ami_int4, 0, NULL, "int4 handler");
|
add_isr (IRQ5, ami_int5, 0, NULL, "int5 handler");
|
add_isr (IRQ5, ami_int5, 0, NULL, "int5 handler");
|
add_isr (IRQ6, ami_int6, 0, NULL, "int6 handler");
|
add_isr (IRQ6, ami_int6, 0, NULL, "int6 handler");
|
add_isr (IRQ7, ami_int7, 0, NULL, "int7 handler");
|
add_isr (IRQ7, ami_int7, 0, NULL, "int7 handler");
|
|
|
/* hook in the CIA interrupts */
|
/* hook in the CIA interrupts */
|
ciadata[0].ciaptr = &ciaa;
|
ciadata[0].ciaptr = &ciaa;
|
ciadata[0].baseirq = IRQ_AMIGA_CIAA_TA;
|
ciadata[0].baseirq = IRQ_AMIGA_CIAA_TA;
|
add_isr (IRQ_AMIGA_PORTS, ami_intcia, 0, NULL, "Amiga CIAA");
|
add_isr (IRQ_AMIGA_PORTS, ami_intcia, 0, NULL, "Amiga CIAA");
|
ciadata[1].ciaptr = &ciab;
|
ciadata[1].ciaptr = &ciab;
|
ciadata[1].baseirq = IRQ_AMIGA_CIAB_TA;
|
ciadata[1].baseirq = IRQ_AMIGA_CIAB_TA;
|
add_isr (IRQ_AMIGA_EXTER, ami_intcia, 0, NULL, "Amiga CIAB");
|
add_isr (IRQ_AMIGA_EXTER, ami_intcia, 0, NULL, "Amiga CIAB");
|
|
|
/* turn off all interrupts and enable the master interrupt bit */
|
/* turn off all interrupts and enable the master interrupt bit */
|
custom.intena = 0x7fff;
|
custom.intena = 0x7fff;
|
custom.intreq = 0x7fff;
|
custom.intreq = 0x7fff;
|
custom.intena = 0xc000;
|
custom.intena = 0xc000;
|
|
|
/* turn off all CIA interrupts */
|
/* turn off all CIA interrupts */
|
ciaa.icr = 0x7f;
|
ciaa.icr = 0x7f;
|
ciab.icr = 0x7f;
|
ciab.icr = 0x7f;
|
|
|
/* clear any pending CIA interrupts */
|
/* clear any pending CIA interrupts */
|
i = ciaa.icr;
|
i = ciaa.icr;
|
i = ciab.icr;
|
i = ciab.icr;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* The builtin Amiga hardware interrupt handlers.
|
* The builtin Amiga hardware interrupt handlers.
|
*/
|
*/
|
|
|
static void ami_int1 (int irq, struct pt_regs *fp, void *data)
|
static void ami_int1 (int irq, struct pt_regs *fp, void *data)
|
{
|
{
|
ushort ints = custom.intreqr & custom.intenar;
|
ushort ints = custom.intreqr & custom.intenar;
|
|
|
/* if serial transmit buffer empty, interrupt */
|
/* if serial transmit buffer empty, interrupt */
|
if (ints & IF_TBE) {
|
if (ints & IF_TBE) {
|
if (ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)]) {
|
if (ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)]) {
|
call_isr_list (IRQ_AMIGA_TBE,
|
call_isr_list (IRQ_AMIGA_TBE,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)], fp);
|
/*
|
/*
|
* don't acknowledge....
|
* don't acknowledge....
|
* allow serial code to turn off interrupts, but
|
* allow serial code to turn off interrupts, but
|
* leave it pending so that when interrupts are
|
* leave it pending so that when interrupts are
|
* turned on, transmission will resume
|
* turned on, transmission will resume
|
*/
|
*/
|
} else
|
} else
|
/* acknowledge the interrupt */
|
/* acknowledge the interrupt */
|
custom.intreq = IF_TBE;
|
custom.intreq = IF_TBE;
|
}
|
}
|
|
|
/* if floppy disk transfer complete, interrupt */
|
/* if floppy disk transfer complete, interrupt */
|
if (ints & IF_DSKBLK) {
|
if (ints & IF_DSKBLK) {
|
call_isr_list (IRQ_AMIGA_DSKBLK,
|
call_isr_list (IRQ_AMIGA_DSKBLK,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_DSKBLK)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_DSKBLK)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_DSKBLK;
|
custom.intreq = IF_DSKBLK;
|
}
|
}
|
|
|
/* if software interrupt set, interrupt */
|
/* if software interrupt set, interrupt */
|
if (ints & IF_SOFT) {
|
if (ints & IF_SOFT) {
|
call_isr_list (IRQ_AMIGA_SOFT,
|
call_isr_list (IRQ_AMIGA_SOFT,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_SOFT)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_SOFT)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_SOFT;
|
custom.intreq = IF_SOFT;
|
}
|
}
|
}
|
}
|
|
|
static void ami_int2 (int irq, struct pt_regs *fp, void *data)
|
static void ami_int2 (int irq, struct pt_regs *fp, void *data)
|
{
|
{
|
ushort ints = custom.intreqr & custom.intenar;
|
ushort ints = custom.intreqr & custom.intenar;
|
|
|
if (ints & IF_PORTS) {
|
if (ints & IF_PORTS) {
|
/* call routines which have hooked into the PORTS interrupt */
|
/* call routines which have hooked into the PORTS interrupt */
|
call_isr_list (IRQ_AMIGA_PORTS,
|
call_isr_list (IRQ_AMIGA_PORTS,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_PORTS)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_PORTS)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_PORTS;
|
custom.intreq = IF_PORTS;
|
}
|
}
|
}
|
}
|
|
|
static void ami_int3 (int irq, struct pt_regs *fp, void *data)
|
static void ami_int3 (int irq, struct pt_regs *fp, void *data)
|
{
|
{
|
ushort ints = custom.intreqr & custom.intenar;
|
ushort ints = custom.intreqr & custom.intenar;
|
|
|
/* if a copper interrupt */
|
/* if a copper interrupt */
|
if (ints & IF_COPER) {
|
if (ints & IF_COPER) {
|
call_isr_list (IRQ_AMIGA_COPPER,
|
call_isr_list (IRQ_AMIGA_COPPER,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_COPPER)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_COPPER)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_COPER;
|
custom.intreq = IF_COPER;
|
}
|
}
|
|
|
/* if a vertical blank interrupt */
|
/* if a vertical blank interrupt */
|
if (ints & IF_VERTB) {
|
if (ints & IF_VERTB) {
|
call_isr_list (IRQ_AMIGA_VERTB,
|
call_isr_list (IRQ_AMIGA_VERTB,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_VERTB)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_VERTB)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_VERTB;
|
custom.intreq = IF_VERTB;
|
}
|
}
|
|
|
/* if a blitter interrupt */
|
/* if a blitter interrupt */
|
if (ints & IF_BLIT) {
|
if (ints & IF_BLIT) {
|
call_isr_list (IRQ_AMIGA_BLIT,
|
call_isr_list (IRQ_AMIGA_BLIT,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_BLIT)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_BLIT)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_BLIT;
|
custom.intreq = IF_BLIT;
|
}
|
}
|
}
|
}
|
|
|
static void ami_int4 (int irq, struct pt_regs *fp, void *data)
|
static void ami_int4 (int irq, struct pt_regs *fp, void *data)
|
{
|
{
|
ushort ints = custom.intreqr & custom.intenar;
|
ushort ints = custom.intreqr & custom.intenar;
|
|
|
/* if audio 0 interrupt */
|
/* if audio 0 interrupt */
|
if (ints & IF_AUD0) {
|
if (ints & IF_AUD0) {
|
call_isr_list (IRQ_AMIGA_AUD0,
|
call_isr_list (IRQ_AMIGA_AUD0,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_AUD0)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_AUD0)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_AUD0;
|
custom.intreq = IF_AUD0;
|
}
|
}
|
|
|
/* if audio 1 interrupt */
|
/* if audio 1 interrupt */
|
if (ints & IF_AUD1) {
|
if (ints & IF_AUD1) {
|
call_isr_list (IRQ_AMIGA_AUD1,
|
call_isr_list (IRQ_AMIGA_AUD1,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_AUD1)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_AUD1)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_AUD1;
|
custom.intreq = IF_AUD1;
|
}
|
}
|
|
|
/* if audio 2 interrupt */
|
/* if audio 2 interrupt */
|
if (ints & IF_AUD2) {
|
if (ints & IF_AUD2) {
|
call_isr_list (IRQ_AMIGA_AUD2,
|
call_isr_list (IRQ_AMIGA_AUD2,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_AUD2)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_AUD2)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_AUD2;
|
custom.intreq = IF_AUD2;
|
}
|
}
|
|
|
/* if audio 3 interrupt */
|
/* if audio 3 interrupt */
|
if (ints & IF_AUD3) {
|
if (ints & IF_AUD3) {
|
call_isr_list (IRQ_AMIGA_AUD3,
|
call_isr_list (IRQ_AMIGA_AUD3,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_AUD3)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_AUD3)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_AUD3;
|
custom.intreq = IF_AUD3;
|
}
|
}
|
}
|
}
|
|
|
static void ami_int5 (int irq, struct pt_regs *fp, void *data)
|
static void ami_int5 (int irq, struct pt_regs *fp, void *data)
|
{
|
{
|
ushort ints = custom.intreqr & custom.intenar;
|
ushort ints = custom.intreqr & custom.intenar;
|
|
|
/* if serial receive buffer full interrupt */
|
/* if serial receive buffer full interrupt */
|
if (ints & IF_RBF) {
|
if (ints & IF_RBF) {
|
if (ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)]) {
|
if (ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)]) {
|
call_isr_list (IRQ_AMIGA_RBF,
|
call_isr_list (IRQ_AMIGA_RBF,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)], fp);
|
/* don't acknowledge ; leave that for the handler */
|
/* don't acknowledge ; leave that for the handler */
|
} else
|
} else
|
/* acknowledge the interrupt */
|
/* acknowledge the interrupt */
|
custom.intreq = IF_RBF;
|
custom.intreq = IF_RBF;
|
}
|
}
|
|
|
/* if a disk sync interrupt */
|
/* if a disk sync interrupt */
|
if (ints & IF_DSKSYN) {
|
if (ints & IF_DSKSYN) {
|
call_isr_list (IRQ_AMIGA_DSKSYN,
|
call_isr_list (IRQ_AMIGA_DSKSYN,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_DSKSYN)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_DSKSYN)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_DSKSYN;
|
custom.intreq = IF_DSKSYN;
|
}
|
}
|
}
|
}
|
|
|
static void ami_int6 (int irq, struct pt_regs *fp, void *data)
|
static void ami_int6 (int irq, struct pt_regs *fp, void *data)
|
{
|
{
|
ushort ints = custom.intreqr & custom.intenar;
|
ushort ints = custom.intreqr & custom.intenar;
|
|
|
if (ints & IF_EXTER) {
|
if (ints & IF_EXTER) {
|
/* call routines which have hooked into the EXTER interrupt */
|
/* call routines which have hooked into the EXTER interrupt */
|
call_isr_list (IRQ_AMIGA_EXTER,
|
call_isr_list (IRQ_AMIGA_EXTER,
|
ami_lists[IRQ_IDX(IRQ_AMIGA_EXTER)], fp);
|
ami_lists[IRQ_IDX(IRQ_AMIGA_EXTER)], fp);
|
|
|
/* acknowledge */
|
/* acknowledge */
|
custom.intreq = IF_EXTER;
|
custom.intreq = IF_EXTER;
|
}
|
}
|
}
|
}
|
|
|
static void ami_int7 (int irq, struct pt_regs *fp, void *data)
|
static void ami_int7 (int irq, struct pt_regs *fp, void *data)
|
{
|
{
|
panic ("level 7 interrupt received\n");
|
panic ("level 7 interrupt received\n");
|
}
|
}
|
|
|
static void ami_intcia (int irq, struct pt_regs *fp, void *data)
|
static void ami_intcia (int irq, struct pt_regs *fp, void *data)
|
{
|
{
|
/* check CIA interrupts */
|
/* check CIA interrupts */
|
struct ciadata *datap;
|
struct ciadata *datap;
|
u_char cia_ints;
|
u_char cia_ints;
|
|
|
/* setup data correctly */
|
/* setup data correctly */
|
if (irq == IRQ_AMIGA_PORTS)
|
if (irq == IRQ_AMIGA_PORTS)
|
datap = &ciadata[0];
|
datap = &ciadata[0];
|
else
|
else
|
datap = &ciadata[1];
|
datap = &ciadata[1];
|
|
|
cia_ints = datap->ciaptr->icr;
|
cia_ints = datap->ciaptr->icr;
|
|
|
/* if timer A interrupt */
|
/* if timer A interrupt */
|
if (cia_ints & CIA_ICR_TA)
|
if (cia_ints & CIA_ICR_TA)
|
call_isr_list (IRQ_AMIGA_CIAA_TA,
|
call_isr_list (IRQ_AMIGA_CIAA_TA,
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TA)], fp);
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TA)], fp);
|
|
|
/* if timer B interrupt */
|
/* if timer B interrupt */
|
if (cia_ints & CIA_ICR_TB)
|
if (cia_ints & CIA_ICR_TB)
|
call_isr_list (IRQ_AMIGA_CIAA_TB,
|
call_isr_list (IRQ_AMIGA_CIAA_TB,
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TB)], fp);
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TB)], fp);
|
|
|
/* if the alarm interrupt */
|
/* if the alarm interrupt */
|
if (cia_ints & CIA_ICR_ALRM)
|
if (cia_ints & CIA_ICR_ALRM)
|
call_isr_list (IRQ_AMIGA_CIAA_ALRM,
|
call_isr_list (IRQ_AMIGA_CIAA_ALRM,
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_ALRM)], fp);
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_ALRM)], fp);
|
|
|
/* if serial port interrupt (keyboard) */
|
/* if serial port interrupt (keyboard) */
|
if (cia_ints & CIA_ICR_SP)
|
if (cia_ints & CIA_ICR_SP)
|
call_isr_list (IRQ_AMIGA_CIAA_SP,
|
call_isr_list (IRQ_AMIGA_CIAA_SP,
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_SP)], fp);
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_SP)], fp);
|
|
|
/* if flag interrupt (parallel port) */
|
/* if flag interrupt (parallel port) */
|
if (cia_ints & CIA_ICR_FLG)
|
if (cia_ints & CIA_ICR_FLG)
|
call_isr_list (IRQ_AMIGA_CIAA_FLG,
|
call_isr_list (IRQ_AMIGA_CIAA_FLG,
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_FLG)], fp);
|
ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_FLG)], fp);
|
}
|
}
|
|
|
/*
|
/*
|
* amiga_add_isr : add an interrupt service routine for a particular
|
* amiga_add_isr : add an interrupt service routine for a particular
|
* machine specific interrupt source.
|
* machine specific interrupt source.
|
* If the addition was successful, it returns 1, otherwise
|
* If the addition was successful, it returns 1, otherwise
|
* it returns 0. It will fail if another routine is already
|
* it returns 0. It will fail if another routine is already
|
* bound into the specified source.
|
* bound into the specified source.
|
* Note that the "pri" argument is currently unused.
|
* Note that the "pri" argument is currently unused.
|
*/
|
*/
|
|
|
int amiga_add_isr (unsigned long source, isrfunc isr, int pri, void
|
int amiga_add_isr (unsigned long source, isrfunc isr, int pri, void
|
*data, char *name)
|
*data, char *name)
|
{
|
{
|
unsigned long amiga_source = source & ~IRQ_MACHSPEC;
|
unsigned long amiga_source = source & ~IRQ_MACHSPEC;
|
isr_node_t *p;
|
isr_node_t *p;
|
|
|
if (amiga_source > NUM_AMIGA_SOURCES) {
|
if (amiga_source > NUM_AMIGA_SOURCES) {
|
printk ("amiga_add_isr: Unknown interrupt source %ld\n", source);
|
printk ("amiga_add_isr: Unknown interrupt source %ld\n", source);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
p = new_isr_node();
|
p = new_isr_node();
|
if (p == NULL)
|
if (p == NULL)
|
return 0;
|
return 0;
|
p->isr = isr;
|
p->isr = isr;
|
p->pri = pri;
|
p->pri = pri;
|
p->data = data;
|
p->data = data;
|
p->name = name;
|
p->name = name;
|
p->next = NULL;
|
p->next = NULL;
|
insert_isr (&ami_lists[amiga_source], p);
|
insert_isr (&ami_lists[amiga_source], p);
|
|
|
/* enable the interrupt */
|
/* enable the interrupt */
|
custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
|
custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
|
|
|
/* if a CIAA interrupt, enable the appropriate CIA ICR bit */
|
/* if a CIAA interrupt, enable the appropriate CIA ICR bit */
|
if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
|
if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
|
ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
|
ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
|
|
|
/* if a CIAB interrupt, enable the appropriate CIA ICR bit */
|
/* if a CIAB interrupt, enable the appropriate CIA ICR bit */
|
if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
|
if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
|
ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
|
ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
|
|
|
return 1;
|
return 1;
|
}
|
}
|
|
|
int amiga_remove_isr (unsigned long source, isrfunc isr, void *data)
|
int amiga_remove_isr (unsigned long source, isrfunc isr, void *data)
|
{
|
{
|
unsigned long amiga_source = source & ~IRQ_MACHSPEC;
|
unsigned long amiga_source = source & ~IRQ_MACHSPEC;
|
|
|
if (amiga_source > NUM_AMIGA_SOURCES) {
|
if (amiga_source > NUM_AMIGA_SOURCES) {
|
printk ("amiga_remove_isr: Unknown interrupt source %ld\n", source);
|
printk ("amiga_remove_isr: Unknown interrupt source %ld\n", source);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
delete_isr (&ami_lists[amiga_source], isr, data);
|
delete_isr (&ami_lists[amiga_source], isr, data);
|
|
|
if (ami_lists[amiga_source] == NULL) {
|
if (ami_lists[amiga_source] == NULL) {
|
/* disable the interrupt */
|
/* disable the interrupt */
|
custom.intena = ami_intena_vals[amiga_source];
|
custom.intena = ami_intena_vals[amiga_source];
|
|
|
/* if a CIAA interrupt, disable the appropriate CIA ICR bit */
|
/* if a CIAA interrupt, disable the appropriate CIA ICR bit */
|
if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
|
if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
|
ciaa.icr = 1 << (source - IRQ_AMIGA_CIAA_TA);
|
ciaa.icr = 1 << (source - IRQ_AMIGA_CIAA_TA);
|
|
|
/* if a CIAB interrupt, disable the appropriate CIA ICR bit */
|
/* if a CIAB interrupt, disable the appropriate CIA ICR bit */
|
if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
|
if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
|
ciab.icr = 1 << (source - IRQ_AMIGA_CIAB_TA);
|
ciab.icr = 1 << (source - IRQ_AMIGA_CIAB_TA);
|
}
|
}
|
|
|
return 1;
|
return 1;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Enable/disable a particular machine specific interrupt source.
|
* Enable/disable a particular machine specific interrupt source.
|
* Note that this may affect other interrupts in case of a shared interrupt.
|
* Note that this may affect other interrupts in case of a shared interrupt.
|
*/
|
*/
|
|
|
void amiga_enable_irq(unsigned int source)
|
void amiga_enable_irq(unsigned int source)
|
{
|
{
|
unsigned long amiga_source = source & ~IRQ_MACHSPEC;
|
unsigned long amiga_source = source & ~IRQ_MACHSPEC;
|
|
|
if (amiga_source > NUM_AMIGA_SOURCES) {
|
if (amiga_source > NUM_AMIGA_SOURCES) {
|
printk("amiga_enable_irq: Unknown interrupt source %d\n", source);
|
printk("amiga_enable_irq: Unknown interrupt source %d\n", source);
|
return;
|
return;
|
}
|
}
|
|
|
/* enable the interrupt */
|
/* enable the interrupt */
|
custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
|
custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
|
|
|
/* if a CIAA interrupt, enable the appropriate CIA ICR bit */
|
/* if a CIAA interrupt, enable the appropriate CIA ICR bit */
|
if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
|
if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
|
ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
|
ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
|
|
|
/* if a CIAB interrupt, enable the appropriate CIA ICR bit */
|
/* if a CIAB interrupt, enable the appropriate CIA ICR bit */
|
if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
|
if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
|
ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
|
ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
|
|
|
}
|
}
|
|
|
void amiga_disable_irq(unsigned int source)
|
void amiga_disable_irq(unsigned int source)
|
{
|
{
|
unsigned long amiga_source = source & ~IRQ_MACHSPEC;
|
unsigned long amiga_source = source & ~IRQ_MACHSPEC;
|
|
|
if (amiga_source > NUM_AMIGA_SOURCES) {
|
if (amiga_source > NUM_AMIGA_SOURCES) {
|
printk("amiga_disable_irq: Unknown interrupt source %d\n", source);
|
printk("amiga_disable_irq: Unknown interrupt source %d\n", source);
|
return;
|
return;
|
}
|
}
|
|
|
/* disable the interrupt */
|
/* disable the interrupt */
|
custom.intena = ami_intena_vals[amiga_source];
|
custom.intena = ami_intena_vals[amiga_source];
|
|
|
/* if a CIAA interrupt, disable the appropriate CIA ICR bit */
|
/* if a CIAA interrupt, disable the appropriate CIA ICR bit */
|
if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
|
if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
|
ciaa.icr = 1 << (source - IRQ_AMIGA_CIAA_TA);
|
ciaa.icr = 1 << (source - IRQ_AMIGA_CIAA_TA);
|
|
|
/* if a CIAB interrupt, disable the appropriate CIA ICR bit */
|
/* if a CIAB interrupt, disable the appropriate CIA ICR bit */
|
if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
|
if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
|
ciab.icr = 1 << (source - IRQ_AMIGA_CIAB_TA);
|
ciab.icr = 1 << (source - IRQ_AMIGA_CIAB_TA);
|
|
|
}
|
}
|
|
|
|
|
int amiga_get_irq_list( char *buf, int len )
|
int amiga_get_irq_list( char *buf, int len )
|
{ int i;
|
{ int i;
|
isr_node_t *p;
|
isr_node_t *p;
|
|
|
for( i = 0; i < NUM_AMIGA_SOURCES; ++i ) {
|
for( i = 0; i < NUM_AMIGA_SOURCES; ++i ) {
|
if (!ami_lists[i])
|
if (!ami_lists[i])
|
continue;
|
continue;
|
len += sprintf( buf+len, "ami %2d: ???????? ", i );
|
len += sprintf( buf+len, "ami %2d: ???????? ", i );
|
for( p = ami_lists[i]; p; p = p->next ) {
|
for( p = ami_lists[i]; p; p = p->next ) {
|
len += sprintf( buf+len, "%s\n", p->name );
|
len += sprintf( buf+len, "%s\n", p->name );
|
if (p->next)
|
if (p->next)
|
len += sprintf( buf+len, " " );
|
len += sprintf( buf+len, " " );
|
}
|
}
|
}
|
}
|
|
|
return( len );
|
return( len );
|
}
|
}
|
|
|