root/arch/m68k/amiga/amiints.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. amiga_init_INTS
  2. ami_int1
  3. ami_int2
  4. ami_int3
  5. ami_int4
  6. ami_int5
  7. ami_int6
  8. ami_int7
  9. ami_intcia
  10. amiga_add_isr
  11. amiga_get_irq_list

   1 /*
   2  * amiints.c -- Amiga Linux interrupt handling code
   3  *
   4  * This file is subject to the terms and conditions of the GNU General Public
   5  * License.  See the file README.legal in the main directory of this archive
   6  * for more details.
   7  *
   8  */
   9 
  10 #include <linux/types.h>
  11 #include <linux/kernel.h>
  12 #include <linux/sched.h>
  13 
  14 #include <asm/system.h>
  15 #include <asm/irq.h>
  16 #include <asm/traps.h>
  17 #include <asm/amigahw.h>
  18 #include <asm/amigaints.h>
  19 
  20 /* isr node variables for amiga interrupt sources */
  21 static isr_node_t *ami_lists[NUM_AMIGA_SOURCES];
  22 
  23 static const ushort ami_intena_vals[NUM_AMIGA_SOURCES] = {
  24     IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
  25     IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_PORTS, IF_PORTS, IF_PORTS,
  26     IF_PORTS, IF_PORTS, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER,
  27     IF_SOFT, IF_PORTS, IF_EXTER
  28     };
  29 
  30 struct ciadata
  31 {
  32     volatile struct CIA *ciaptr;
  33     unsigned long       baseirq;
  34 } ciadata[2];
  35 
  36 /*
  37  * index into ami_lists for IRQs.  CIA IRQs are special, because
  38  * the same cia interrupt handler is used for both CIAs.
  39  */
  40 #define IRQ_IDX(source) (source & ~IRQ_MACHSPEC)
  41 #define CIA_IRQ_IDX(source) (IRQ_IDX(datap->baseirq) \
  42                              +(source-IRQ_AMIGA_CIAA_TA))
  43 
  44 /*
  45  * void amiga_init_INTS (void)
  46  *
  47  * Parameters:  None
  48  *
  49  * Returns:     Nothing
  50  *
  51  * This function should be called during kernel startup to initialize
  52  * the amiga IRQ handling routines.
  53  */
  54 
  55 static void
  56     ami_int1(int irq, struct pt_regs *fp, void *data),
  57     ami_int2(int irq, struct pt_regs *fp, void *data),
  58     ami_int3(int irq, struct pt_regs *fp, void *data),
  59     ami_int4(int irq, struct pt_regs *fp, void *data),
  60     ami_int5(int irq, struct pt_regs *fp, void *data),
  61     ami_int6(int irq, struct pt_regs *fp, void *data),
  62     ami_int7(int irq, struct pt_regs *fp, void *data),
  63     ami_intcia(int irq, struct pt_regs *fp, void *data);
  64 
  65 void amiga_init_INTS (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67     int i;
  68 
  69     /* initialize handlers */
  70     for (i = 0; i < NUM_AMIGA_SOURCES; i++)
  71         ami_lists[i] = NULL;
  72 
  73     add_isr (IRQ1, ami_int1, 0, NULL, "int1 handler");
  74     add_isr (IRQ2, ami_int2, 0, NULL, "int2 handler");
  75     add_isr (IRQ3, ami_int3, 0, NULL, "int3 handler");
  76     add_isr (IRQ4, ami_int4, 0, NULL, "int4 handler");
  77     add_isr (IRQ5, ami_int5, 0, NULL, "int5 handler");
  78     add_isr (IRQ6, ami_int6, 0, NULL, "int6 handler");
  79     add_isr (IRQ7, ami_int7, 0, NULL, "int7 handler");
  80 
  81     /* hook in the CIA interrupts */
  82     ciadata[0].ciaptr = &ciaa;
  83     ciadata[0].baseirq = IRQ_AMIGA_CIAA_TA;
  84     add_isr (IRQ_AMIGA_PORTS, ami_intcia, 0, NULL, "Amiga CIAA");
  85     ciadata[1].ciaptr = &ciab;
  86     ciadata[1].baseirq = IRQ_AMIGA_CIAB_TA;
  87     add_isr (IRQ_AMIGA_EXTER, ami_intcia, 0, NULL, "Amiga CIAB");
  88 
  89     /* turn off all interrupts and enable the master interrupt bit */
  90     custom.intena = 0x7fff;
  91     custom.intreq = 0x7fff;
  92     custom.intena = 0xc000;
  93 
  94     /* turn off all CIA interrupts */
  95     ciaa.icr = 0x7f;
  96     ciab.icr = 0x7f;
  97 
  98     /* clear any pending CIA interrupts */
  99     i = ciaa.icr;
 100     i = ciab.icr;
 101 }
 102 
 103 
 104 /*
 105  * The builtin Amiga hardware interrupt handlers.
 106  */
 107 
 108 static void ami_int1 (int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110     ushort ints = custom.intreqr & custom.intenar;
 111 
 112     /* if serial transmit buffer empty, interrupt */
 113     if (ints & IF_TBE) {
 114         if (ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)]) {
 115             call_isr_list (IRQ_AMIGA_TBE,
 116                            ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)], fp);
 117             /* 
 118              * don't acknowledge.... 
 119              * allow serial code to turn off interrupts, but
 120              * leave it pending so that when interrupts are
 121              * turned on, transmission will resume
 122              */
 123         } else
 124             /* acknowledge the interrupt */
 125             custom.intreq = IF_TBE;
 126     }
 127 
 128     /* if floppy disk transfer complete, interrupt */
 129     if (ints & IF_DSKBLK) {
 130         call_isr_list (IRQ_AMIGA_DSKBLK,
 131                        ami_lists[IRQ_IDX(IRQ_AMIGA_DSKBLK)], fp);
 132 
 133         /* acknowledge */
 134         custom.intreq = IF_DSKBLK;
 135     }
 136 
 137     /* if software interrupt set, interrupt */
 138     if (ints & IF_SOFT) {
 139         call_isr_list (IRQ_AMIGA_SOFT,
 140                        ami_lists[IRQ_IDX(IRQ_AMIGA_SOFT)], fp);
 141 
 142         /* acknowledge */
 143         custom.intreq = IF_SOFT;
 144     }
 145 }
 146 
 147 static void ami_int2 (int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149     ushort ints = custom.intreqr & custom.intenar;
 150 
 151     if (ints & IF_PORTS) {
 152         /* call routines which have hooked into the PORTS interrupt */
 153         call_isr_list (IRQ_AMIGA_PORTS,
 154                        ami_lists[IRQ_IDX(IRQ_AMIGA_PORTS)], fp);
 155 
 156         /* acknowledge */
 157         custom.intreq = IF_PORTS;
 158     }
 159 }
 160 
 161 static void ami_int3 (int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163     ushort ints = custom.intreqr & custom.intenar;
 164 
 165     /* if a copper interrupt */
 166     if (ints & IF_COPER) {
 167         call_isr_list (IRQ_AMIGA_COPPER,
 168                        ami_lists[IRQ_IDX(IRQ_AMIGA_COPPER)], fp);
 169 
 170         /* acknowledge */
 171         custom.intreq = IF_COPER;
 172     }
 173 
 174     /* if a vertical blank interrupt */
 175     if (ints & IF_VERTB) {
 176         call_isr_list (IRQ_AMIGA_VERTB,
 177                        ami_lists[IRQ_IDX(IRQ_AMIGA_VERTB)], fp);
 178 
 179         /* acknowledge */
 180         custom.intreq = IF_VERTB;
 181     }
 182 
 183     /* if a blitter interrupt */
 184     if (ints & IF_BLIT) {
 185         call_isr_list (IRQ_AMIGA_BLIT,
 186                        ami_lists[IRQ_IDX(IRQ_AMIGA_BLIT)], fp);
 187 
 188         /* acknowledge */
 189         custom.intreq = IF_BLIT;
 190     }
 191 }
 192 
 193 static void ami_int4 (int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195     ushort ints = custom.intreqr & custom.intenar;
 196 
 197     /* if audio 0 interrupt */
 198     if (ints & IF_AUD0) {
 199         call_isr_list (IRQ_AMIGA_AUD0,
 200                        ami_lists[IRQ_IDX(IRQ_AMIGA_AUD0)], fp);
 201 
 202         /* acknowledge */
 203         custom.intreq = IF_AUD0;
 204     }
 205 
 206     /* if audio 1 interrupt */
 207     if (ints & IF_AUD1) {
 208         call_isr_list (IRQ_AMIGA_AUD1,
 209                        ami_lists[IRQ_IDX(IRQ_AMIGA_AUD1)], fp);
 210 
 211         /* acknowledge */
 212         custom.intreq = IF_AUD1;
 213     }
 214 
 215     /* if audio 2 interrupt */
 216     if (ints & IF_AUD2) {
 217         call_isr_list (IRQ_AMIGA_AUD2,
 218                        ami_lists[IRQ_IDX(IRQ_AMIGA_AUD2)], fp);
 219 
 220         /* acknowledge */
 221         custom.intreq = IF_AUD2;
 222     }
 223 
 224     /* if audio 3 interrupt */
 225     if (ints & IF_AUD3) {
 226         call_isr_list (IRQ_AMIGA_AUD3,
 227                        ami_lists[IRQ_IDX(IRQ_AMIGA_AUD3)], fp);
 228 
 229         /* acknowledge */
 230         custom.intreq = IF_AUD3;
 231     }
 232 }
 233 
 234 static void ami_int5 (int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236     ushort ints = custom.intreqr & custom.intenar;
 237 
 238     /* if serial receive buffer full interrupt */
 239     if (ints & IF_RBF) {
 240         if (ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)]) {
 241             call_isr_list (IRQ_AMIGA_RBF,
 242                            ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)], fp);
 243             /* don't acknowledge ; leave that for the handler */
 244         } else
 245             /* acknowledge the interrupt */
 246             custom.intreq = IF_RBF;
 247     }
 248 
 249     /* if a disk sync interrupt */
 250     if (ints & IF_DSKSYN) {
 251         call_isr_list (IRQ_AMIGA_DSKSYN,
 252                        ami_lists[IRQ_IDX(IRQ_AMIGA_DSKSYN)], fp);
 253 
 254         /* acknowledge */
 255         custom.intreq = IF_DSKSYN;
 256     }
 257 }
 258 
 259 static void ami_int6 (int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 260 {
 261     ushort ints = custom.intreqr & custom.intenar;
 262 
 263     if (ints & IF_EXTER) {
 264         /* call routines which have hooked into the EXTER interrupt */
 265         call_isr_list (IRQ_AMIGA_EXTER,
 266                        ami_lists[IRQ_IDX(IRQ_AMIGA_EXTER)], fp);
 267 
 268         /* acknowledge */
 269         custom.intreq = IF_EXTER;
 270     }
 271 }
 272 
 273 static void ami_int7 (int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275     panic ("level 7 interrupt received\n");
 276 }
 277 
 278 static void ami_intcia (int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 279 {
 280     /* check CIA interrupts */
 281     struct ciadata *datap;
 282     u_char cia_ints;
 283 
 284     /* setup data correctly */
 285     if (irq == IRQ_AMIGA_PORTS)
 286             datap = &ciadata[0];
 287     else
 288             datap = &ciadata[1];
 289 
 290     cia_ints = datap->ciaptr->icr;
 291 
 292     /* if timer A interrupt */
 293     if (cia_ints & CIA_ICR_TA)
 294         call_isr_list (IRQ_AMIGA_CIAA_TA,
 295                        ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TA)], fp);
 296 
 297     /* if timer B interrupt */
 298     if (cia_ints & CIA_ICR_TB)
 299         call_isr_list (IRQ_AMIGA_CIAA_TB,
 300                        ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TB)], fp);
 301 
 302     /* if the alarm interrupt */
 303     if (cia_ints & CIA_ICR_ALRM)
 304         call_isr_list (IRQ_AMIGA_CIAA_ALRM,
 305                        ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_ALRM)], fp);
 306 
 307     /* if serial port interrupt (keyboard) */
 308     if (cia_ints & CIA_ICR_SP)
 309         call_isr_list (IRQ_AMIGA_CIAA_SP,
 310                        ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_SP)], fp);
 311 
 312     /* if flag interrupt (parallel port) */
 313     if (cia_ints & CIA_ICR_FLG)
 314         call_isr_list (IRQ_AMIGA_CIAA_FLG,
 315                        ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_FLG)], fp);
 316 }
 317 
 318 /*
 319  * amiga_add_isr : add an interrupt service routine for a particular
 320  *                 machine specific interrupt source.
 321  *                 If the addition was successful, it returns 1, otherwise
 322  *                 it returns 0.  It will fail if another routine is already
 323  *                 bound into the specified source.
 324  *   Note that the "pri" argument is currently unused.
 325  */
 326 
 327 int amiga_add_isr (unsigned long source, isrfunc isr, int pri, void
     /* [previous][next][first][last][top][bottom][index][help] */
 328                    *data, char *name)
 329 {
 330     unsigned long amiga_source = source & ~IRQ_MACHSPEC;
 331     isr_node_t *p;
 332 
 333     if (amiga_source > NUM_AMIGA_SOURCES) {
 334         printk ("amiga_add_isr: Unknown interrupt source %ld\n", source);
 335         return 0;
 336     }
 337 
 338     p = new_isr_node();
 339     p->isr = isr;
 340     p->pri = pri;
 341     p->data = data;
 342     p->name = name;
 343     p->next = NULL;
 344     insert_isr (&ami_lists[amiga_source], p);
 345 
 346     /* enable the interrupt */
 347     custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
 348 
 349     /* if a CIAA interrupt, enable the appropriate CIA ICR bit */
 350     if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
 351         ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
 352 
 353     /* if a CIAB interrupt, enable the appropriate CIA ICR bit */
 354     if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
 355         ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
 356 
 357     return 1;
 358 }
 359 
 360 int amiga_get_irq_list( char *buf, int len )
     /* [previous][next][first][last][top][bottom][index][help] */
 361 {       int                     i;
 362     isr_node_t  *p;
 363 
 364         for( i = 0; i < NUM_AMIGA_SOURCES; ++i ) {
 365                 if (!ami_lists[i])
 366                         continue;
 367                 len += sprintf( buf+len, "ami  %2d: ???????? ", i );
 368                 for( p = ami_lists[i]; p; p = p->next ) {
 369                         len += sprintf( buf+len, "%s\n", p->name );
 370                         if (p->next)
 371                                 len += sprintf( buf+len, "                  " );
 372                 }
 373         }
 374         
 375         return( len );
 376 }

/* [previous][next][first][last][top][bottom][index][help] */