OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [m68k/] [amiga/] [amiints.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1623 jcastillo
/*
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 COPYING 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)
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)
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)
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)
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)
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)
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)
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)
274
{
275
    panic ("level 7 interrupt received\n");
276
}
277
 
278
static void ami_intcia (int irq, struct pt_regs *fp, void *data)
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
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
    if (p == NULL)
340
        return 0;
341
    p->isr = isr;
342
    p->pri = pri;
343
    p->data = data;
344
    p->name = name;
345
    p->next = NULL;
346
    insert_isr (&ami_lists[amiga_source], p);
347
 
348
    /* enable the interrupt */
349
    custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
350
 
351
    /* if a CIAA interrupt, enable the appropriate CIA ICR bit */
352
    if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
353
        ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
354
 
355
    /* if a CIAB interrupt, enable the appropriate CIA ICR bit */
356
    if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
357
        ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
358
 
359
    return 1;
360
}
361
 
362
int amiga_remove_isr (unsigned long source, isrfunc isr, void *data)
363
{
364
    unsigned long amiga_source = source & ~IRQ_MACHSPEC;
365
 
366
    if (amiga_source > NUM_AMIGA_SOURCES) {
367
        printk ("amiga_remove_isr: Unknown interrupt source %ld\n", source);
368
        return 0;
369
    }
370
 
371
    delete_isr (&ami_lists[amiga_source], isr, data);
372
 
373
    if (ami_lists[amiga_source] == NULL) {
374
        /* disable the interrupt */
375
        custom.intena = ami_intena_vals[amiga_source];
376
 
377
        /* if a CIAA interrupt, disable the appropriate CIA ICR bit */
378
        if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
379
            ciaa.icr = 1 << (source - IRQ_AMIGA_CIAA_TA);
380
 
381
        /* if a CIAB interrupt, disable the appropriate CIA ICR bit */
382
        if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
383
            ciab.icr = 1 << (source - IRQ_AMIGA_CIAB_TA);
384
    }
385
 
386
    return 1;
387
}
388
 
389
 
390
/*
391
 * Enable/disable a particular machine specific interrupt source.
392
 * Note that this may affect other interrupts in case of a shared interrupt.
393
 */
394
 
395
void amiga_enable_irq(unsigned int source)
396
{
397
    unsigned long amiga_source = source & ~IRQ_MACHSPEC;
398
 
399
    if (amiga_source > NUM_AMIGA_SOURCES) {
400
        printk("amiga_enable_irq: Unknown interrupt source %d\n", source);
401
        return;
402
    }
403
 
404
    /* enable the interrupt */
405
    custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
406
 
407
    /* if a CIAA interrupt, enable the appropriate CIA ICR bit */
408
    if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
409
        ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
410
 
411
    /* if a CIAB interrupt, enable the appropriate CIA ICR bit */
412
    if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
413
        ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
414
 
415
}
416
 
417
void amiga_disable_irq(unsigned int source)
418
{
419
    unsigned long amiga_source = source & ~IRQ_MACHSPEC;
420
 
421
    if (amiga_source > NUM_AMIGA_SOURCES) {
422
        printk("amiga_disable_irq: Unknown interrupt source %d\n", source);
423
        return;
424
    }
425
 
426
    /* disable the interrupt */
427
    custom.intena = ami_intena_vals[amiga_source];
428
 
429
    /* if a CIAA interrupt, disable the appropriate CIA ICR bit */
430
    if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
431
        ciaa.icr = 1 << (source - IRQ_AMIGA_CIAA_TA);
432
 
433
    /* if a CIAB interrupt, disable the appropriate CIA ICR bit */
434
    if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
435
        ciab.icr = 1 << (source - IRQ_AMIGA_CIAB_TA);
436
 
437
}
438
 
439
 
440
int amiga_get_irq_list( char *buf, int len )
441
{       int                     i;
442
    isr_node_t  *p;
443
 
444
        for( i = 0; i < NUM_AMIGA_SOURCES; ++i ) {
445
                if (!ami_lists[i])
446
                        continue;
447
                len += sprintf( buf+len, "ami  %2d: ???????? ", i );
448
                for( p = ami_lists[i]; p; p = p->next ) {
449
                        len += sprintf( buf+len, "%s\n", p->name );
450
                        if (p->next)
451
                                len += sprintf( buf+len, "                  " );
452
                }
453
        }
454
 
455
        return( len );
456
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.