Commit 69961c375288bdab7604e0bb1c8d22999bb8a347
Committed by
Linus Torvalds
1 parent
da96d0b58a
Exists in
master
and in
20 other branches
[PATCH] m68k/Atari: Interrupt updates
Misc Atari fixes: - initialize correct number of atari irqs - silence vbl interrupt until it's used by atafb - use mdelay() to read clock if necessary Signed-off-by: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 3 changed files with 15 additions and 4 deletions Inline Diff
arch/m68k/atari/ataints.c
1 | /* | 1 | /* |
2 | * arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code | 2 | * arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code |
3 | * | 3 | * |
4 | * 5/2/94 Roman Hodek: | 4 | * 5/2/94 Roman Hodek: |
5 | * Added support for TT interrupts; setup for TT SCU (may someone has | 5 | * Added support for TT interrupts; setup for TT SCU (may someone has |
6 | * twiddled there and we won't get the right interrupts :-() | 6 | * twiddled there and we won't get the right interrupts :-() |
7 | * | 7 | * |
8 | * Major change: The device-independent code in m68k/ints.c didn't know | 8 | * Major change: The device-independent code in m68k/ints.c didn't know |
9 | * about non-autovec ints yet. It hardcoded the number of possible ints to | 9 | * about non-autovec ints yet. It hardcoded the number of possible ints to |
10 | * 7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the | 10 | * 7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the |
11 | * number of possible ints a constant defined in interrupt.h, which is | 11 | * number of possible ints a constant defined in interrupt.h, which is |
12 | * 47 for the Atari. So we can call request_irq() for all Atari interrupts | 12 | * 47 for the Atari. So we can call request_irq() for all Atari interrupts |
13 | * just the normal way. Additionally, all vectors >= 48 are initialized to | 13 | * just the normal way. Additionally, all vectors >= 48 are initialized to |
14 | * call trap() instead of inthandler(). This must be changed here, too. | 14 | * call trap() instead of inthandler(). This must be changed here, too. |
15 | * | 15 | * |
16 | * 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>: | 16 | * 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>: |
17 | * Corrected a bug in atari_add_isr() which rejected all SCC | 17 | * Corrected a bug in atari_add_isr() which rejected all SCC |
18 | * interrupt sources if there were no TT MFP! | 18 | * interrupt sources if there were no TT MFP! |
19 | * | 19 | * |
20 | * 12/13/95: New interface functions atari_level_triggered_int() and | 20 | * 12/13/95: New interface functions atari_level_triggered_int() and |
21 | * atari_register_vme_int() as support for level triggered VME interrupts. | 21 | * atari_register_vme_int() as support for level triggered VME interrupts. |
22 | * | 22 | * |
23 | * 02/12/96: (Roman) | 23 | * 02/12/96: (Roman) |
24 | * Total rewrite of Atari interrupt handling, for new scheme see comments | 24 | * Total rewrite of Atari interrupt handling, for new scheme see comments |
25 | * below. | 25 | * below. |
26 | * | 26 | * |
27 | * 1996-09-03 lars brinkhoff <f93labr@dd.chalmers.se>: | 27 | * 1996-09-03 lars brinkhoff <f93labr@dd.chalmers.se>: |
28 | * Added new function atari_unregister_vme_int(), and | 28 | * Added new function atari_unregister_vme_int(), and |
29 | * modified atari_register_vme_int() as well as IS_VALID_INTNO() | 29 | * modified atari_register_vme_int() as well as IS_VALID_INTNO() |
30 | * to work with it. | 30 | * to work with it. |
31 | * | 31 | * |
32 | * This file is subject to the terms and conditions of the GNU General Public | 32 | * This file is subject to the terms and conditions of the GNU General Public |
33 | * License. See the file COPYING in the main directory of this archive | 33 | * License. See the file COPYING in the main directory of this archive |
34 | * for more details. | 34 | * for more details. |
35 | * | 35 | * |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <linux/types.h> | 38 | #include <linux/types.h> |
39 | #include <linux/kernel.h> | 39 | #include <linux/kernel.h> |
40 | #include <linux/kernel_stat.h> | 40 | #include <linux/kernel_stat.h> |
41 | #include <linux/init.h> | 41 | #include <linux/init.h> |
42 | #include <linux/seq_file.h> | 42 | #include <linux/seq_file.h> |
43 | 43 | ||
44 | #include <asm/system.h> | 44 | #include <asm/system.h> |
45 | #include <asm/traps.h> | 45 | #include <asm/traps.h> |
46 | 46 | ||
47 | #include <asm/atarihw.h> | 47 | #include <asm/atarihw.h> |
48 | #include <asm/atariints.h> | 48 | #include <asm/atariints.h> |
49 | #include <asm/atari_stdma.h> | 49 | #include <asm/atari_stdma.h> |
50 | #include <asm/irq.h> | 50 | #include <asm/irq.h> |
51 | #include <asm/entry.h> | 51 | #include <asm/entry.h> |
52 | 52 | ||
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Atari interrupt handling scheme: | 55 | * Atari interrupt handling scheme: |
56 | * -------------------------------- | 56 | * -------------------------------- |
57 | * | 57 | * |
58 | * All interrupt source have an internal number (defined in | 58 | * All interrupt source have an internal number (defined in |
59 | * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP, | 59 | * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP, |
60 | * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can | 60 | * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can |
61 | * be allocated by atari_register_vme_int(). | 61 | * be allocated by atari_register_vme_int(). |
62 | * | 62 | * |
63 | * Each interrupt can be of three types: | 63 | * Each interrupt can be of three types: |
64 | * | 64 | * |
65 | * - SLOW: The handler runs with all interrupts enabled, except the one it | 65 | * - SLOW: The handler runs with all interrupts enabled, except the one it |
66 | * was called by (to avoid reentering). This should be the usual method. | 66 | * was called by (to avoid reentering). This should be the usual method. |
67 | * But it is currently possible only for MFP ints, since only the MFP | 67 | * But it is currently possible only for MFP ints, since only the MFP |
68 | * offers an easy way to mask interrupts. | 68 | * offers an easy way to mask interrupts. |
69 | * | 69 | * |
70 | * - FAST: The handler runs with all interrupts disabled. This should be used | 70 | * - FAST: The handler runs with all interrupts disabled. This should be used |
71 | * only for really fast handlers, that just do actions immediately | 71 | * only for really fast handlers, that just do actions immediately |
72 | * necessary, and let the rest do a bottom half or task queue. | 72 | * necessary, and let the rest do a bottom half or task queue. |
73 | * | 73 | * |
74 | * - PRIORITIZED: The handler can be interrupted by higher-level ints | 74 | * - PRIORITIZED: The handler can be interrupted by higher-level ints |
75 | * (greater IPL, no MFP priorities!). This is the method of choice for ints | 75 | * (greater IPL, no MFP priorities!). This is the method of choice for ints |
76 | * which should be slow, but are not from a MFP. | 76 | * which should be slow, but are not from a MFP. |
77 | * | 77 | * |
78 | * The feature of more than one handler for one int source is still there, but | 78 | * The feature of more than one handler for one int source is still there, but |
79 | * only applicable if all handers are of the same type. To not slow down | 79 | * only applicable if all handers are of the same type. To not slow down |
80 | * processing of ints with only one handler by the chaining feature, the list | 80 | * processing of ints with only one handler by the chaining feature, the list |
81 | * calling function atari_call_irq_list() is only plugged in at the time the | 81 | * calling function atari_call_irq_list() is only plugged in at the time the |
82 | * second handler is registered. | 82 | * second handler is registered. |
83 | * | 83 | * |
84 | * Implementation notes: For fast-as-possible int handling, there are separate | 84 | * Implementation notes: For fast-as-possible int handling, there are separate |
85 | * entry points for each type (slow/fast/prio). The assembler handler calls | 85 | * entry points for each type (slow/fast/prio). The assembler handler calls |
86 | * the irq directly in the usual case, no C wrapper is involved. In case of | 86 | * the irq directly in the usual case, no C wrapper is involved. In case of |
87 | * multiple handlers, atari_call_irq_list() is registered as handler and calls | 87 | * multiple handlers, atari_call_irq_list() is registered as handler and calls |
88 | * in turn the real irq's. To ease access from assembler level to the irq | 88 | * in turn the real irq's. To ease access from assembler level to the irq |
89 | * function pointer and accompanying data, these two are stored in a separate | 89 | * function pointer and accompanying data, these two are stored in a separate |
90 | * array, irq_handler[]. The rest of data (type, name) are put into a second | 90 | * array, irq_handler[]. The rest of data (type, name) are put into a second |
91 | * array, irq_param, that is accessed from C only. For each slow interrupt (32 | 91 | * array, irq_param, that is accessed from C only. For each slow interrupt (32 |
92 | * in all) there are separate handler functions, which makes it possible to | 92 | * in all) there are separate handler functions, which makes it possible to |
93 | * hard-code the MFP register address and value, are necessary to mask the | 93 | * hard-code the MFP register address and value, are necessary to mask the |
94 | * int. If there'd be only one generic function, lots of calculations would be | 94 | * int. If there'd be only one generic function, lots of calculations would be |
95 | * needed to determine MFP register and int mask from the vector number :-( | 95 | * needed to determine MFP register and int mask from the vector number :-( |
96 | * | 96 | * |
97 | * Furthermore, slow ints may not lower the IPL below its previous value | 97 | * Furthermore, slow ints may not lower the IPL below its previous value |
98 | * (before the int happened). This is needed so that an int of class PRIO, on | 98 | * (before the int happened). This is needed so that an int of class PRIO, on |
99 | * that this int may be stacked, cannot be reentered. This feature is | 99 | * that this int may be stacked, cannot be reentered. This feature is |
100 | * implemented as follows: If the stack frame format is 1 (throwaway), the int | 100 | * implemented as follows: If the stack frame format is 1 (throwaway), the int |
101 | * is not stacked, and the IPL is anded with 0xfbff, resulting in a new level | 101 | * is not stacked, and the IPL is anded with 0xfbff, resulting in a new level |
102 | * 2, which still blocks the HSYNC, but no interrupts of interest. If the | 102 | * 2, which still blocks the HSYNC, but no interrupts of interest. If the |
103 | * frame format is 0, the int is nested, and the old IPL value can be found in | 103 | * frame format is 0, the int is nested, and the old IPL value can be found in |
104 | * the sr copy in the frame. | 104 | * the sr copy in the frame. |
105 | */ | 105 | */ |
106 | 106 | ||
107 | #if 0 | 107 | #if 0 |
108 | 108 | ||
109 | #define NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES) | 109 | #define NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES) |
110 | 110 | ||
111 | typedef void (*asm_irq_handler)(void); | 111 | typedef void (*asm_irq_handler)(void); |
112 | 112 | ||
113 | struct irqhandler { | 113 | struct irqhandler { |
114 | irqreturn_t (*handler)(int, void *, struct pt_regs *); | 114 | irqreturn_t (*handler)(int, void *, struct pt_regs *); |
115 | void *dev_id; | 115 | void *dev_id; |
116 | }; | 116 | }; |
117 | 117 | ||
118 | struct irqparam { | 118 | struct irqparam { |
119 | unsigned long flags; | 119 | unsigned long flags; |
120 | const char *devname; | 120 | const char *devname; |
121 | }; | 121 | }; |
122 | 122 | ||
123 | /* | 123 | /* |
124 | * Array with irq's and their parameter data. This array is accessed from low | 124 | * Array with irq's and their parameter data. This array is accessed from low |
125 | * level assembler code, so an element size of 8 allows usage of index scaling | 125 | * level assembler code, so an element size of 8 allows usage of index scaling |
126 | * addressing mode. | 126 | * addressing mode. |
127 | */ | 127 | */ |
128 | static struct irqhandler irq_handler[NUM_INT_SOURCES]; | 128 | static struct irqhandler irq_handler[NUM_INT_SOURCES]; |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * This array hold the rest of parameters of int handlers: type | 131 | * This array hold the rest of parameters of int handlers: type |
132 | * (slow,fast,prio) and the name of the handler. These values are only | 132 | * (slow,fast,prio) and the name of the handler. These values are only |
133 | * accessed from C | 133 | * accessed from C |
134 | */ | 134 | */ |
135 | static struct irqparam irq_param[NUM_INT_SOURCES]; | 135 | static struct irqparam irq_param[NUM_INT_SOURCES]; |
136 | 136 | ||
137 | /* check for valid int number (complex, sigh...) */ | 137 | /* check for valid int number (complex, sigh...) */ |
138 | #define IS_VALID_INTNO(n) \ | 138 | #define IS_VALID_INTNO(n) \ |
139 | ((n) > 0 && \ | 139 | ((n) > 0 && \ |
140 | /* autovec and ST-MFP ok anyway */ \ | 140 | /* autovec and ST-MFP ok anyway */ \ |
141 | (((n) < TTMFP_SOURCE_BASE) || \ | 141 | (((n) < TTMFP_SOURCE_BASE) || \ |
142 | /* TT-MFP ok if present */ \ | 142 | /* TT-MFP ok if present */ \ |
143 | ((n) >= TTMFP_SOURCE_BASE && (n) < SCC_SOURCE_BASE && \ | 143 | ((n) >= TTMFP_SOURCE_BASE && (n) < SCC_SOURCE_BASE && \ |
144 | ATARIHW_PRESENT(TT_MFP)) || \ | 144 | ATARIHW_PRESENT(TT_MFP)) || \ |
145 | /* SCC ok if present and number even */ \ | 145 | /* SCC ok if present and number even */ \ |
146 | ((n) >= SCC_SOURCE_BASE && (n) < VME_SOURCE_BASE && \ | 146 | ((n) >= SCC_SOURCE_BASE && (n) < VME_SOURCE_BASE && \ |
147 | !((n) & 1) && ATARIHW_PRESENT(SCC)) || \ | 147 | !((n) & 1) && ATARIHW_PRESENT(SCC)) || \ |
148 | /* greater numbers ok if they are registered VME vectors */ \ | 148 | /* greater numbers ok if they are registered VME vectors */ \ |
149 | ((n) >= VME_SOURCE_BASE && (n) < VME_SOURCE_BASE + VME_MAX_SOURCES && \ | 149 | ((n) >= VME_SOURCE_BASE && (n) < VME_SOURCE_BASE + VME_MAX_SOURCES && \ |
150 | free_vme_vec_bitmap & (1 << ((n) - VME_SOURCE_BASE))))) | 150 | free_vme_vec_bitmap & (1 << ((n) - VME_SOURCE_BASE))))) |
151 | 151 | ||
152 | 152 | ||
153 | /* | 153 | /* |
154 | * Here start the assembler entry points for interrupts | 154 | * Here start the assembler entry points for interrupts |
155 | */ | 155 | */ |
156 | 156 | ||
157 | #define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void) | 157 | #define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void) |
158 | 158 | ||
159 | #define BUILD_SLOW_IRQ(n) \ | 159 | #define BUILD_SLOW_IRQ(n) \ |
160 | asmlinkage void IRQ_NAME(n); \ | 160 | asmlinkage void IRQ_NAME(n); \ |
161 | /* Dummy function to allow asm with operands. */ \ | 161 | /* Dummy function to allow asm with operands. */ \ |
162 | void atari_slow_irq_##n##_dummy (void) { \ | 162 | void atari_slow_irq_##n##_dummy (void) { \ |
163 | __asm__ (__ALIGN_STR "\n" \ | 163 | __asm__ (__ALIGN_STR "\n" \ |
164 | "atari_slow_irq_" #n "_handler:\t" \ | 164 | "atari_slow_irq_" #n "_handler:\t" \ |
165 | " addl %6,%5\n" /* preempt_count() += HARDIRQ_OFFSET */ \ | 165 | " addl %6,%5\n" /* preempt_count() += HARDIRQ_OFFSET */ \ |
166 | SAVE_ALL_INT "\n" \ | 166 | SAVE_ALL_INT "\n" \ |
167 | GET_CURRENT(%%d0) "\n" \ | 167 | GET_CURRENT(%%d0) "\n" \ |
168 | " andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \ | 168 | " andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \ |
169 | /* get old IPL from stack frame */ \ | 169 | /* get old IPL from stack frame */ \ |
170 | " bfextu %%sp@(%c2){#5,#3},%%d0\n" \ | 170 | " bfextu %%sp@(%c2){#5,#3},%%d0\n" \ |
171 | " movew %%sr,%%d1\n" \ | 171 | " movew %%sr,%%d1\n" \ |
172 | " bfins %%d0,%%d1{#21,#3}\n" \ | 172 | " bfins %%d0,%%d1{#21,#3}\n" \ |
173 | " movew %%d1,%%sr\n" /* set IPL = previous value */ \ | 173 | " movew %%d1,%%sr\n" /* set IPL = previous value */ \ |
174 | " addql #1,%a0\n" \ | 174 | " addql #1,%a0\n" \ |
175 | " lea %a1,%%a0\n" \ | 175 | " lea %a1,%%a0\n" \ |
176 | " pea %%sp@\n" /* push addr of frame */ \ | 176 | " pea %%sp@\n" /* push addr of frame */ \ |
177 | " movel %%a0@(4),%%sp@-\n" /* push handler data */ \ | 177 | " movel %%a0@(4),%%sp@-\n" /* push handler data */ \ |
178 | " pea (%c3+8)\n" /* push int number */ \ | 178 | " pea (%c3+8)\n" /* push int number */ \ |
179 | " movel %%a0@,%%a0\n" \ | 179 | " movel %%a0@,%%a0\n" \ |
180 | " jbsr %%a0@\n" /* call the handler */ \ | 180 | " jbsr %%a0@\n" /* call the handler */ \ |
181 | " addql #8,%%sp\n" \ | 181 | " addql #8,%%sp\n" \ |
182 | " addql #4,%%sp\n" \ | 182 | " addql #4,%%sp\n" \ |
183 | " orw #0x0600,%%sr\n" \ | 183 | " orw #0x0600,%%sr\n" \ |
184 | " andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \ | 184 | " andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \ |
185 | " orb #(1<<(%c3&7)),%a4:w\n" /* now unmask the int again */ \ | 185 | " orb #(1<<(%c3&7)),%a4:w\n" /* now unmask the int again */ \ |
186 | " jbra ret_from_interrupt\n" \ | 186 | " jbra ret_from_interrupt\n" \ |
187 | : : "i" (&kstat_cpu(0).irqs[n+8]), "i" (&irq_handler[n+8]), \ | 187 | : : "i" (&kstat_cpu(0).irqs[n+8]), "i" (&irq_handler[n+8]), \ |
188 | "n" (PT_OFF_SR), "n" (n), \ | 188 | "n" (PT_OFF_SR), "n" (n), \ |
189 | "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \ | 189 | "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \ |
190 | : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)), \ | 190 | : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)), \ |
191 | "m" (preempt_count()), "di" (HARDIRQ_OFFSET) \ | 191 | "m" (preempt_count()), "di" (HARDIRQ_OFFSET) \ |
192 | ); \ | 192 | ); \ |
193 | for (;;); /* fake noreturn */ \ | 193 | for (;;); /* fake noreturn */ \ |
194 | } | 194 | } |
195 | 195 | ||
196 | BUILD_SLOW_IRQ(0); | 196 | BUILD_SLOW_IRQ(0); |
197 | BUILD_SLOW_IRQ(1); | 197 | BUILD_SLOW_IRQ(1); |
198 | BUILD_SLOW_IRQ(2); | 198 | BUILD_SLOW_IRQ(2); |
199 | BUILD_SLOW_IRQ(3); | 199 | BUILD_SLOW_IRQ(3); |
200 | BUILD_SLOW_IRQ(4); | 200 | BUILD_SLOW_IRQ(4); |
201 | BUILD_SLOW_IRQ(5); | 201 | BUILD_SLOW_IRQ(5); |
202 | BUILD_SLOW_IRQ(6); | 202 | BUILD_SLOW_IRQ(6); |
203 | BUILD_SLOW_IRQ(7); | 203 | BUILD_SLOW_IRQ(7); |
204 | BUILD_SLOW_IRQ(8); | 204 | BUILD_SLOW_IRQ(8); |
205 | BUILD_SLOW_IRQ(9); | 205 | BUILD_SLOW_IRQ(9); |
206 | BUILD_SLOW_IRQ(10); | 206 | BUILD_SLOW_IRQ(10); |
207 | BUILD_SLOW_IRQ(11); | 207 | BUILD_SLOW_IRQ(11); |
208 | BUILD_SLOW_IRQ(12); | 208 | BUILD_SLOW_IRQ(12); |
209 | BUILD_SLOW_IRQ(13); | 209 | BUILD_SLOW_IRQ(13); |
210 | BUILD_SLOW_IRQ(14); | 210 | BUILD_SLOW_IRQ(14); |
211 | BUILD_SLOW_IRQ(15); | 211 | BUILD_SLOW_IRQ(15); |
212 | BUILD_SLOW_IRQ(16); | 212 | BUILD_SLOW_IRQ(16); |
213 | BUILD_SLOW_IRQ(17); | 213 | BUILD_SLOW_IRQ(17); |
214 | BUILD_SLOW_IRQ(18); | 214 | BUILD_SLOW_IRQ(18); |
215 | BUILD_SLOW_IRQ(19); | 215 | BUILD_SLOW_IRQ(19); |
216 | BUILD_SLOW_IRQ(20); | 216 | BUILD_SLOW_IRQ(20); |
217 | BUILD_SLOW_IRQ(21); | 217 | BUILD_SLOW_IRQ(21); |
218 | BUILD_SLOW_IRQ(22); | 218 | BUILD_SLOW_IRQ(22); |
219 | BUILD_SLOW_IRQ(23); | 219 | BUILD_SLOW_IRQ(23); |
220 | BUILD_SLOW_IRQ(24); | 220 | BUILD_SLOW_IRQ(24); |
221 | BUILD_SLOW_IRQ(25); | 221 | BUILD_SLOW_IRQ(25); |
222 | BUILD_SLOW_IRQ(26); | 222 | BUILD_SLOW_IRQ(26); |
223 | BUILD_SLOW_IRQ(27); | 223 | BUILD_SLOW_IRQ(27); |
224 | BUILD_SLOW_IRQ(28); | 224 | BUILD_SLOW_IRQ(28); |
225 | BUILD_SLOW_IRQ(29); | 225 | BUILD_SLOW_IRQ(29); |
226 | BUILD_SLOW_IRQ(30); | 226 | BUILD_SLOW_IRQ(30); |
227 | BUILD_SLOW_IRQ(31); | 227 | BUILD_SLOW_IRQ(31); |
228 | 228 | ||
229 | asm_irq_handler slow_handlers[32] = { | 229 | asm_irq_handler slow_handlers[32] = { |
230 | [0] = atari_slow_irq_0_handler, | 230 | [0] = atari_slow_irq_0_handler, |
231 | [1] = atari_slow_irq_1_handler, | 231 | [1] = atari_slow_irq_1_handler, |
232 | [2] = atari_slow_irq_2_handler, | 232 | [2] = atari_slow_irq_2_handler, |
233 | [3] = atari_slow_irq_3_handler, | 233 | [3] = atari_slow_irq_3_handler, |
234 | [4] = atari_slow_irq_4_handler, | 234 | [4] = atari_slow_irq_4_handler, |
235 | [5] = atari_slow_irq_5_handler, | 235 | [5] = atari_slow_irq_5_handler, |
236 | [6] = atari_slow_irq_6_handler, | 236 | [6] = atari_slow_irq_6_handler, |
237 | [7] = atari_slow_irq_7_handler, | 237 | [7] = atari_slow_irq_7_handler, |
238 | [8] = atari_slow_irq_8_handler, | 238 | [8] = atari_slow_irq_8_handler, |
239 | [9] = atari_slow_irq_9_handler, | 239 | [9] = atari_slow_irq_9_handler, |
240 | [10] = atari_slow_irq_10_handler, | 240 | [10] = atari_slow_irq_10_handler, |
241 | [11] = atari_slow_irq_11_handler, | 241 | [11] = atari_slow_irq_11_handler, |
242 | [12] = atari_slow_irq_12_handler, | 242 | [12] = atari_slow_irq_12_handler, |
243 | [13] = atari_slow_irq_13_handler, | 243 | [13] = atari_slow_irq_13_handler, |
244 | [14] = atari_slow_irq_14_handler, | 244 | [14] = atari_slow_irq_14_handler, |
245 | [15] = atari_slow_irq_15_handler, | 245 | [15] = atari_slow_irq_15_handler, |
246 | [16] = atari_slow_irq_16_handler, | 246 | [16] = atari_slow_irq_16_handler, |
247 | [17] = atari_slow_irq_17_handler, | 247 | [17] = atari_slow_irq_17_handler, |
248 | [18] = atari_slow_irq_18_handler, | 248 | [18] = atari_slow_irq_18_handler, |
249 | [19] = atari_slow_irq_19_handler, | 249 | [19] = atari_slow_irq_19_handler, |
250 | [20] = atari_slow_irq_20_handler, | 250 | [20] = atari_slow_irq_20_handler, |
251 | [21] = atari_slow_irq_21_handler, | 251 | [21] = atari_slow_irq_21_handler, |
252 | [22] = atari_slow_irq_22_handler, | 252 | [22] = atari_slow_irq_22_handler, |
253 | [23] = atari_slow_irq_23_handler, | 253 | [23] = atari_slow_irq_23_handler, |
254 | [24] = atari_slow_irq_24_handler, | 254 | [24] = atari_slow_irq_24_handler, |
255 | [25] = atari_slow_irq_25_handler, | 255 | [25] = atari_slow_irq_25_handler, |
256 | [26] = atari_slow_irq_26_handler, | 256 | [26] = atari_slow_irq_26_handler, |
257 | [27] = atari_slow_irq_27_handler, | 257 | [27] = atari_slow_irq_27_handler, |
258 | [28] = atari_slow_irq_28_handler, | 258 | [28] = atari_slow_irq_28_handler, |
259 | [29] = atari_slow_irq_29_handler, | 259 | [29] = atari_slow_irq_29_handler, |
260 | [30] = atari_slow_irq_30_handler, | 260 | [30] = atari_slow_irq_30_handler, |
261 | [31] = atari_slow_irq_31_handler | 261 | [31] = atari_slow_irq_31_handler |
262 | }; | 262 | }; |
263 | 263 | ||
264 | asmlinkage void atari_fast_irq_handler( void ); | 264 | asmlinkage void atari_fast_irq_handler( void ); |
265 | asmlinkage void atari_prio_irq_handler( void ); | 265 | asmlinkage void atari_prio_irq_handler( void ); |
266 | 266 | ||
267 | /* Dummy function to allow asm with operands. */ | 267 | /* Dummy function to allow asm with operands. */ |
268 | void atari_fast_prio_irq_dummy (void) { | 268 | void atari_fast_prio_irq_dummy (void) { |
269 | __asm__ (__ALIGN_STR "\n" | 269 | __asm__ (__ALIGN_STR "\n" |
270 | "atari_fast_irq_handler:\n\t" | 270 | "atari_fast_irq_handler:\n\t" |
271 | "orw #0x700,%%sr\n" /* disable all interrupts */ | 271 | "orw #0x700,%%sr\n" /* disable all interrupts */ |
272 | "atari_prio_irq_handler:\n\t" | 272 | "atari_prio_irq_handler:\n\t" |
273 | "addl %3,%2\n\t" /* preempt_count() += HARDIRQ_OFFSET */ | 273 | "addl %3,%2\n\t" /* preempt_count() += HARDIRQ_OFFSET */ |
274 | SAVE_ALL_INT "\n\t" | 274 | SAVE_ALL_INT "\n\t" |
275 | GET_CURRENT(%%d0) "\n\t" | 275 | GET_CURRENT(%%d0) "\n\t" |
276 | /* get vector number from stack frame and convert to source */ | 276 | /* get vector number from stack frame and convert to source */ |
277 | "bfextu %%sp@(%c1){#4,#10},%%d0\n\t" | 277 | "bfextu %%sp@(%c1){#4,#10},%%d0\n\t" |
278 | "subw #(0x40-8),%%d0\n\t" | 278 | "subw #(0x40-8),%%d0\n\t" |
279 | "jpl 1f\n\t" | 279 | "jpl 1f\n\t" |
280 | "addw #(0x40-8-0x18),%%d0\n" | 280 | "addw #(0x40-8-0x18),%%d0\n" |
281 | "1:\tlea %a0,%%a0\n\t" | 281 | "1:\tlea %a0,%%a0\n\t" |
282 | "addql #1,%%a0@(%%d0:l:4)\n\t" | 282 | "addql #1,%%a0@(%%d0:l:4)\n\t" |
283 | "lea irq_handler,%%a0\n\t" | 283 | "lea irq_handler,%%a0\n\t" |
284 | "lea %%a0@(%%d0:l:8),%%a0\n\t" | 284 | "lea %%a0@(%%d0:l:8),%%a0\n\t" |
285 | "pea %%sp@\n\t" /* push frame address */ | 285 | "pea %%sp@\n\t" /* push frame address */ |
286 | "movel %%a0@(4),%%sp@-\n\t" /* push handler data */ | 286 | "movel %%a0@(4),%%sp@-\n\t" /* push handler data */ |
287 | "movel %%d0,%%sp@-\n\t" /* push int number */ | 287 | "movel %%d0,%%sp@-\n\t" /* push int number */ |
288 | "movel %%a0@,%%a0\n\t" | 288 | "movel %%a0@,%%a0\n\t" |
289 | "jsr %%a0@\n\t" /* and call the handler */ | 289 | "jsr %%a0@\n\t" /* and call the handler */ |
290 | "addql #8,%%sp\n\t" | 290 | "addql #8,%%sp\n\t" |
291 | "addql #4,%%sp\n\t" | 291 | "addql #4,%%sp\n\t" |
292 | "jbra ret_from_interrupt" | 292 | "jbra ret_from_interrupt" |
293 | : : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC), | 293 | : : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC), |
294 | "m" (preempt_count()), "di" (HARDIRQ_OFFSET) | 294 | "m" (preempt_count()), "di" (HARDIRQ_OFFSET) |
295 | ); | 295 | ); |
296 | for (;;); | 296 | for (;;); |
297 | } | 297 | } |
298 | #endif | 298 | #endif |
299 | 299 | ||
300 | /* | 300 | /* |
301 | * Bitmap for free interrupt vector numbers | 301 | * Bitmap for free interrupt vector numbers |
302 | * (new vectors starting from 0x70 can be allocated by | 302 | * (new vectors starting from 0x70 can be allocated by |
303 | * atari_register_vme_int()) | 303 | * atari_register_vme_int()) |
304 | */ | 304 | */ |
305 | static int free_vme_vec_bitmap; | 305 | static int free_vme_vec_bitmap; |
306 | 306 | ||
307 | /* GK: | 307 | /* GK: |
308 | * HBL IRQ handler for Falcon. Nobody needs it :-) | 308 | * HBL IRQ handler for Falcon. Nobody needs it :-) |
309 | * ++andreas: raise ipl to disable further HBLANK interrupts. | 309 | * ++andreas: raise ipl to disable further HBLANK interrupts. |
310 | */ | 310 | */ |
311 | asmlinkage void falcon_hblhandler(void); | 311 | asmlinkage void falcon_hblhandler(void); |
312 | asm(".text\n" | 312 | asm(".text\n" |
313 | __ALIGN_STR "\n\t" | 313 | __ALIGN_STR "\n\t" |
314 | "falcon_hblhandler:\n\t" | 314 | "falcon_hblhandler:\n\t" |
315 | "orw #0x200,%sp@\n\t" /* set saved ipl to 2 */ | 315 | "orw #0x200,%sp@\n\t" /* set saved ipl to 2 */ |
316 | "rte"); | 316 | "rte"); |
317 | 317 | ||
318 | extern void atari_microwire_cmd(int cmd); | 318 | extern void atari_microwire_cmd(int cmd); |
319 | 319 | ||
320 | extern int atari_SCC_reset_done; | 320 | extern int atari_SCC_reset_done; |
321 | 321 | ||
322 | static int atari_startup_irq(unsigned int irq) | 322 | static int atari_startup_irq(unsigned int irq) |
323 | { | 323 | { |
324 | m68k_irq_startup(irq); | 324 | m68k_irq_startup(irq); |
325 | atari_turnon_irq(irq); | 325 | atari_turnon_irq(irq); |
326 | atari_enable_irq(irq); | 326 | atari_enable_irq(irq); |
327 | return 0; | 327 | return 0; |
328 | } | 328 | } |
329 | 329 | ||
330 | static void atari_shutdown_irq(unsigned int irq) | 330 | static void atari_shutdown_irq(unsigned int irq) |
331 | { | 331 | { |
332 | atari_disable_irq(irq); | 332 | atari_disable_irq(irq); |
333 | atari_turnoff_irq(irq); | 333 | atari_turnoff_irq(irq); |
334 | m68k_irq_shutdown(irq); | 334 | m68k_irq_shutdown(irq); |
335 | |||
336 | if (irq == IRQ_AUTO_4) | ||
337 | vectors[VEC_INT4] = falcon_hblhandler; | ||
335 | } | 338 | } |
336 | 339 | ||
337 | static struct irq_controller atari_irq_controller = { | 340 | static struct irq_controller atari_irq_controller = { |
338 | .name = "atari", | 341 | .name = "atari", |
339 | .lock = SPIN_LOCK_UNLOCKED, | 342 | .lock = SPIN_LOCK_UNLOCKED, |
340 | .startup = atari_startup_irq, | 343 | .startup = atari_startup_irq, |
341 | .shutdown = atari_shutdown_irq, | 344 | .shutdown = atari_shutdown_irq, |
342 | .enable = atari_enable_irq, | 345 | .enable = atari_enable_irq, |
343 | .disable = atari_disable_irq, | 346 | .disable = atari_disable_irq, |
344 | }; | 347 | }; |
345 | 348 | ||
346 | /* | 349 | /* |
347 | * void atari_init_IRQ (void) | 350 | * void atari_init_IRQ (void) |
348 | * | 351 | * |
349 | * Parameters: None | 352 | * Parameters: None |
350 | * | 353 | * |
351 | * Returns: Nothing | 354 | * Returns: Nothing |
352 | * | 355 | * |
353 | * This function should be called during kernel startup to initialize | 356 | * This function should be called during kernel startup to initialize |
354 | * the atari IRQ handling routines. | 357 | * the atari IRQ handling routines. |
355 | */ | 358 | */ |
356 | 359 | ||
357 | void __init atari_init_IRQ(void) | 360 | void __init atari_init_IRQ(void) |
358 | { | 361 | { |
359 | m68k_setup_user_interrupt(VEC_USER, 192, NULL); | 362 | m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER, NULL); |
360 | m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1); | 363 | m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1); |
361 | 364 | ||
362 | /* Initialize the MFP(s) */ | 365 | /* Initialize the MFP(s) */ |
363 | 366 | ||
364 | #ifdef ATARI_USE_SOFTWARE_EOI | 367 | #ifdef ATARI_USE_SOFTWARE_EOI |
365 | mfp.vec_adr = 0x48; /* Software EOI-Mode */ | 368 | mfp.vec_adr = 0x48; /* Software EOI-Mode */ |
366 | #else | 369 | #else |
367 | mfp.vec_adr = 0x40; /* Automatic EOI-Mode */ | 370 | mfp.vec_adr = 0x40; /* Automatic EOI-Mode */ |
368 | #endif | 371 | #endif |
369 | mfp.int_en_a = 0x00; /* turn off MFP-Ints */ | 372 | mfp.int_en_a = 0x00; /* turn off MFP-Ints */ |
370 | mfp.int_en_b = 0x00; | 373 | mfp.int_en_b = 0x00; |
371 | mfp.int_mk_a = 0xff; /* no Masking */ | 374 | mfp.int_mk_a = 0xff; /* no Masking */ |
372 | mfp.int_mk_b = 0xff; | 375 | mfp.int_mk_b = 0xff; |
373 | 376 | ||
374 | if (ATARIHW_PRESENT(TT_MFP)) { | 377 | if (ATARIHW_PRESENT(TT_MFP)) { |
375 | #ifdef ATARI_USE_SOFTWARE_EOI | 378 | #ifdef ATARI_USE_SOFTWARE_EOI |
376 | tt_mfp.vec_adr = 0x58; /* Software EOI-Mode */ | 379 | tt_mfp.vec_adr = 0x58; /* Software EOI-Mode */ |
377 | #else | 380 | #else |
378 | tt_mfp.vec_adr = 0x50; /* Automatic EOI-Mode */ | 381 | tt_mfp.vec_adr = 0x50; /* Automatic EOI-Mode */ |
379 | #endif | 382 | #endif |
380 | tt_mfp.int_en_a = 0x00; /* turn off MFP-Ints */ | 383 | tt_mfp.int_en_a = 0x00; /* turn off MFP-Ints */ |
381 | tt_mfp.int_en_b = 0x00; | 384 | tt_mfp.int_en_b = 0x00; |
382 | tt_mfp.int_mk_a = 0xff; /* no Masking */ | 385 | tt_mfp.int_mk_a = 0xff; /* no Masking */ |
383 | tt_mfp.int_mk_b = 0xff; | 386 | tt_mfp.int_mk_b = 0xff; |
384 | } | 387 | } |
385 | 388 | ||
386 | if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) { | 389 | if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) { |
387 | scc.cha_a_ctrl = 9; | 390 | scc.cha_a_ctrl = 9; |
388 | MFPDELAY(); | 391 | MFPDELAY(); |
389 | scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ | 392 | scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ |
390 | } | 393 | } |
391 | 394 | ||
392 | if (ATARIHW_PRESENT(SCU)) { | 395 | if (ATARIHW_PRESENT(SCU)) { |
393 | /* init the SCU if present */ | 396 | /* init the SCU if present */ |
394 | tt_scu.sys_mask = 0x10; /* enable VBL (for the cursor) and | 397 | tt_scu.sys_mask = 0x10; /* enable VBL (for the cursor) and |
395 | * disable HSYNC interrupts (who | 398 | * disable HSYNC interrupts (who |
396 | * needs them?) MFP and SCC are | 399 | * needs them?) MFP and SCC are |
397 | * enabled in VME mask | 400 | * enabled in VME mask |
398 | */ | 401 | */ |
399 | tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ | 402 | tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ |
400 | } else { | 403 | } else { |
401 | /* If no SCU and no Hades, the HSYNC interrupt needs to be | 404 | /* If no SCU and no Hades, the HSYNC interrupt needs to be |
402 | * disabled this way. (Else _inthandler in kernel/sys_call.S | 405 | * disabled this way. (Else _inthandler in kernel/sys_call.S |
403 | * gets overruns) | 406 | * gets overruns) |
404 | */ | 407 | */ |
405 | 408 | ||
406 | if (!MACH_IS_HADES) | 409 | if (!MACH_IS_HADES) { |
407 | vectors[VEC_INT2] = falcon_hblhandler; | 410 | vectors[VEC_INT2] = falcon_hblhandler; |
411 | vectors[VEC_INT4] = falcon_hblhandler; | ||
412 | } | ||
408 | } | 413 | } |
409 | 414 | ||
410 | if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { | 415 | if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { |
411 | /* Initialize the LM1992 Sound Controller to enable | 416 | /* Initialize the LM1992 Sound Controller to enable |
412 | the PSG sound. This is misplaced here, it should | 417 | the PSG sound. This is misplaced here, it should |
413 | be in an atasound_init(), that doesn't exist yet. */ | 418 | be in an atasound_init(), that doesn't exist yet. */ |
414 | atari_microwire_cmd(MW_LM1992_PSG_HIGH); | 419 | atari_microwire_cmd(MW_LM1992_PSG_HIGH); |
415 | } | 420 | } |
416 | 421 | ||
417 | stdma_init(); | 422 | stdma_init(); |
418 | 423 | ||
419 | /* Initialize the PSG: all sounds off, both ports output */ | 424 | /* Initialize the PSG: all sounds off, both ports output */ |
420 | sound_ym.rd_data_reg_sel = 7; | 425 | sound_ym.rd_data_reg_sel = 7; |
421 | sound_ym.wd_data = 0xff; | 426 | sound_ym.wd_data = 0xff; |
422 | } | 427 | } |
423 | 428 | ||
424 | 429 | ||
425 | /* | 430 | /* |
426 | * atari_register_vme_int() returns the number of a free interrupt vector for | 431 | * atari_register_vme_int() returns the number of a free interrupt vector for |
427 | * hardware with a programmable int vector (probably a VME board). | 432 | * hardware with a programmable int vector (probably a VME board). |
428 | */ | 433 | */ |
429 | 434 | ||
430 | unsigned long atari_register_vme_int(void) | 435 | unsigned long atari_register_vme_int(void) |
431 | { | 436 | { |
432 | int i; | 437 | int i; |
433 | 438 | ||
434 | for (i = 0; i < 32; i++) | 439 | for (i = 0; i < 32; i++) |
435 | if ((free_vme_vec_bitmap & (1 << i)) == 0) | 440 | if ((free_vme_vec_bitmap & (1 << i)) == 0) |
436 | break; | 441 | break; |
437 | 442 | ||
438 | if (i == 16) | 443 | if (i == 16) |
439 | return 0; | 444 | return 0; |
440 | 445 | ||
441 | free_vme_vec_bitmap |= 1 << i; | 446 | free_vme_vec_bitmap |= 1 << i; |
442 | return VME_SOURCE_BASE + i; | 447 | return VME_SOURCE_BASE + i; |
443 | } | 448 | } |
444 | 449 | ||
445 | 450 | ||
446 | void atari_unregister_vme_int(unsigned long irq) | 451 | void atari_unregister_vme_int(unsigned long irq) |
447 | { | 452 | { |
448 | if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) { | 453 | if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) { |
449 | irq -= VME_SOURCE_BASE; | 454 | irq -= VME_SOURCE_BASE; |
450 | free_vme_vec_bitmap &= ~(1 << irq); | 455 | free_vme_vec_bitmap &= ~(1 << irq); |
451 | } | 456 | } |
452 | } | 457 | } |
453 | 458 | ||
454 | 459 | ||
455 | 460 |
arch/m68k/atari/time.c
1 | /* | 1 | /* |
2 | * linux/arch/m68k/atari/time.c | 2 | * linux/arch/m68k/atari/time.c |
3 | * | 3 | * |
4 | * Atari time and real time clock stuff | 4 | * Atari time and real time clock stuff |
5 | * | 5 | * |
6 | * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek | 6 | * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek |
7 | * | 7 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 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 | 9 | * License. See the file COPYING in the main directory of this archive |
10 | * for more details. | 10 | * for more details. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/mc146818rtc.h> | 14 | #include <linux/mc146818rtc.h> |
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/rtc.h> | 17 | #include <linux/rtc.h> |
18 | #include <linux/bcd.h> | 18 | #include <linux/bcd.h> |
19 | #include <linux/delay.h> | ||
19 | 20 | ||
20 | #include <asm/atariints.h> | 21 | #include <asm/atariints.h> |
21 | 22 | ||
22 | void __init | 23 | void __init |
23 | atari_sched_init(irq_handler_t timer_routine) | 24 | atari_sched_init(irq_handler_t timer_routine) |
24 | { | 25 | { |
25 | /* set Timer C data Register */ | 26 | /* set Timer C data Register */ |
26 | mfp.tim_dt_c = INT_TICKS; | 27 | mfp.tim_dt_c = INT_TICKS; |
27 | /* start timer C, div = 1:100 */ | 28 | /* start timer C, div = 1:100 */ |
28 | mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; | 29 | mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; |
29 | /* install interrupt service routine for MFP Timer C */ | 30 | /* install interrupt service routine for MFP Timer C */ |
30 | request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, | 31 | request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, |
31 | "timer", timer_routine); | 32 | "timer", timer_routine); |
32 | } | 33 | } |
33 | 34 | ||
34 | /* ++andreas: gettimeoffset fixed to check for pending interrupt */ | 35 | /* ++andreas: gettimeoffset fixed to check for pending interrupt */ |
35 | 36 | ||
36 | #define TICK_SIZE 10000 | 37 | #define TICK_SIZE 10000 |
37 | 38 | ||
38 | /* This is always executed with interrupts disabled. */ | 39 | /* This is always executed with interrupts disabled. */ |
39 | unsigned long atari_gettimeoffset (void) | 40 | unsigned long atari_gettimeoffset (void) |
40 | { | 41 | { |
41 | unsigned long ticks, offset = 0; | 42 | unsigned long ticks, offset = 0; |
42 | 43 | ||
43 | /* read MFP timer C current value */ | 44 | /* read MFP timer C current value */ |
44 | ticks = mfp.tim_dt_c; | 45 | ticks = mfp.tim_dt_c; |
45 | /* The probability of underflow is less than 2% */ | 46 | /* The probability of underflow is less than 2% */ |
46 | if (ticks > INT_TICKS - INT_TICKS / 50) | 47 | if (ticks > INT_TICKS - INT_TICKS / 50) |
47 | /* Check for pending timer interrupt */ | 48 | /* Check for pending timer interrupt */ |
48 | if (mfp.int_pn_b & (1 << 5)) | 49 | if (mfp.int_pn_b & (1 << 5)) |
49 | offset = TICK_SIZE; | 50 | offset = TICK_SIZE; |
50 | 51 | ||
51 | ticks = INT_TICKS - ticks; | 52 | ticks = INT_TICKS - ticks; |
52 | ticks = ticks * 10000L / INT_TICKS; | 53 | ticks = ticks * 10000L / INT_TICKS; |
53 | 54 | ||
54 | return ticks + offset; | 55 | return ticks + offset; |
55 | } | 56 | } |
56 | 57 | ||
57 | 58 | ||
58 | static void mste_read(struct MSTE_RTC *val) | 59 | static void mste_read(struct MSTE_RTC *val) |
59 | { | 60 | { |
60 | #define COPY(v) val->v=(mste_rtc.v & 0xf) | 61 | #define COPY(v) val->v=(mste_rtc.v & 0xf) |
61 | do { | 62 | do { |
62 | COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; | 63 | COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; |
63 | COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; | 64 | COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; |
64 | COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; | 65 | COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; |
65 | COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; | 66 | COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; |
66 | COPY(year_tens) ; | 67 | COPY(year_tens) ; |
67 | /* prevent from reading the clock while it changed */ | 68 | /* prevent from reading the clock while it changed */ |
68 | } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); | 69 | } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); |
69 | #undef COPY | 70 | #undef COPY |
70 | } | 71 | } |
71 | 72 | ||
72 | static void mste_write(struct MSTE_RTC *val) | 73 | static void mste_write(struct MSTE_RTC *val) |
73 | { | 74 | { |
74 | #define COPY(v) mste_rtc.v=val->v | 75 | #define COPY(v) mste_rtc.v=val->v |
75 | do { | 76 | do { |
76 | COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; | 77 | COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; |
77 | COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; | 78 | COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; |
78 | COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; | 79 | COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; |
79 | COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; | 80 | COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; |
80 | COPY(year_tens) ; | 81 | COPY(year_tens) ; |
81 | /* prevent from writing the clock while it changed */ | 82 | /* prevent from writing the clock while it changed */ |
82 | } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); | 83 | } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); |
83 | #undef COPY | 84 | #undef COPY |
84 | } | 85 | } |
85 | 86 | ||
86 | #define RTC_READ(reg) \ | 87 | #define RTC_READ(reg) \ |
87 | ({ unsigned char __val; \ | 88 | ({ unsigned char __val; \ |
88 | (void) atari_writeb(reg,&tt_rtc.regsel); \ | 89 | (void) atari_writeb(reg,&tt_rtc.regsel); \ |
89 | __val = tt_rtc.data; \ | 90 | __val = tt_rtc.data; \ |
90 | __val; \ | 91 | __val; \ |
91 | }) | 92 | }) |
92 | 93 | ||
93 | #define RTC_WRITE(reg,val) \ | 94 | #define RTC_WRITE(reg,val) \ |
94 | do { \ | 95 | do { \ |
95 | atari_writeb(reg,&tt_rtc.regsel); \ | 96 | atari_writeb(reg,&tt_rtc.regsel); \ |
96 | tt_rtc.data = (val); \ | 97 | tt_rtc.data = (val); \ |
97 | } while(0) | 98 | } while(0) |
98 | 99 | ||
99 | 100 | ||
100 | #define HWCLK_POLL_INTERVAL 5 | 101 | #define HWCLK_POLL_INTERVAL 5 |
101 | 102 | ||
102 | int atari_mste_hwclk( int op, struct rtc_time *t ) | 103 | int atari_mste_hwclk( int op, struct rtc_time *t ) |
103 | { | 104 | { |
104 | int hour, year; | 105 | int hour, year; |
105 | int hr24=0; | 106 | int hr24=0; |
106 | struct MSTE_RTC val; | 107 | struct MSTE_RTC val; |
107 | 108 | ||
108 | mste_rtc.mode=(mste_rtc.mode | 1); | 109 | mste_rtc.mode=(mste_rtc.mode | 1); |
109 | hr24=mste_rtc.mon_tens & 1; | 110 | hr24=mste_rtc.mon_tens & 1; |
110 | mste_rtc.mode=(mste_rtc.mode & ~1); | 111 | mste_rtc.mode=(mste_rtc.mode & ~1); |
111 | 112 | ||
112 | if (op) { | 113 | if (op) { |
113 | /* write: prepare values */ | 114 | /* write: prepare values */ |
114 | 115 | ||
115 | val.sec_ones = t->tm_sec % 10; | 116 | val.sec_ones = t->tm_sec % 10; |
116 | val.sec_tens = t->tm_sec / 10; | 117 | val.sec_tens = t->tm_sec / 10; |
117 | val.min_ones = t->tm_min % 10; | 118 | val.min_ones = t->tm_min % 10; |
118 | val.min_tens = t->tm_min / 10; | 119 | val.min_tens = t->tm_min / 10; |
119 | hour = t->tm_hour; | 120 | hour = t->tm_hour; |
120 | if (!hr24) { | 121 | if (!hr24) { |
121 | if (hour > 11) | 122 | if (hour > 11) |
122 | hour += 20 - 12; | 123 | hour += 20 - 12; |
123 | if (hour == 0 || hour == 20) | 124 | if (hour == 0 || hour == 20) |
124 | hour += 12; | 125 | hour += 12; |
125 | } | 126 | } |
126 | val.hr_ones = hour % 10; | 127 | val.hr_ones = hour % 10; |
127 | val.hr_tens = hour / 10; | 128 | val.hr_tens = hour / 10; |
128 | val.day_ones = t->tm_mday % 10; | 129 | val.day_ones = t->tm_mday % 10; |
129 | val.day_tens = t->tm_mday / 10; | 130 | val.day_tens = t->tm_mday / 10; |
130 | val.mon_ones = (t->tm_mon+1) % 10; | 131 | val.mon_ones = (t->tm_mon+1) % 10; |
131 | val.mon_tens = (t->tm_mon+1) / 10; | 132 | val.mon_tens = (t->tm_mon+1) / 10; |
132 | year = t->tm_year - 80; | 133 | year = t->tm_year - 80; |
133 | val.year_ones = year % 10; | 134 | val.year_ones = year % 10; |
134 | val.year_tens = year / 10; | 135 | val.year_tens = year / 10; |
135 | val.weekday = t->tm_wday; | 136 | val.weekday = t->tm_wday; |
136 | mste_write(&val); | 137 | mste_write(&val); |
137 | mste_rtc.mode=(mste_rtc.mode | 1); | 138 | mste_rtc.mode=(mste_rtc.mode | 1); |
138 | val.year_ones = (year % 4); /* leap year register */ | 139 | val.year_ones = (year % 4); /* leap year register */ |
139 | mste_rtc.mode=(mste_rtc.mode & ~1); | 140 | mste_rtc.mode=(mste_rtc.mode & ~1); |
140 | } | 141 | } |
141 | else { | 142 | else { |
142 | mste_read(&val); | 143 | mste_read(&val); |
143 | t->tm_sec = val.sec_ones + val.sec_tens * 10; | 144 | t->tm_sec = val.sec_ones + val.sec_tens * 10; |
144 | t->tm_min = val.min_ones + val.min_tens * 10; | 145 | t->tm_min = val.min_ones + val.min_tens * 10; |
145 | hour = val.hr_ones + val.hr_tens * 10; | 146 | hour = val.hr_ones + val.hr_tens * 10; |
146 | if (!hr24) { | 147 | if (!hr24) { |
147 | if (hour == 12 || hour == 12 + 20) | 148 | if (hour == 12 || hour == 12 + 20) |
148 | hour -= 12; | 149 | hour -= 12; |
149 | if (hour >= 20) | 150 | if (hour >= 20) |
150 | hour += 12 - 20; | 151 | hour += 12 - 20; |
151 | } | 152 | } |
152 | t->tm_hour = hour; | 153 | t->tm_hour = hour; |
153 | t->tm_mday = val.day_ones + val.day_tens * 10; | 154 | t->tm_mday = val.day_ones + val.day_tens * 10; |
154 | t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1; | 155 | t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1; |
155 | t->tm_year = val.year_ones + val.year_tens * 10 + 80; | 156 | t->tm_year = val.year_ones + val.year_tens * 10 + 80; |
156 | t->tm_wday = val.weekday; | 157 | t->tm_wday = val.weekday; |
157 | } | 158 | } |
158 | return 0; | 159 | return 0; |
159 | } | 160 | } |
160 | 161 | ||
161 | int atari_tt_hwclk( int op, struct rtc_time *t ) | 162 | int atari_tt_hwclk( int op, struct rtc_time *t ) |
162 | { | 163 | { |
163 | int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; | 164 | int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; |
164 | unsigned long flags; | 165 | unsigned long flags; |
165 | unsigned char ctrl; | 166 | unsigned char ctrl; |
166 | int pm = 0; | 167 | int pm = 0; |
167 | 168 | ||
168 | ctrl = RTC_READ(RTC_CONTROL); /* control registers are | 169 | ctrl = RTC_READ(RTC_CONTROL); /* control registers are |
169 | * independent from the UIP */ | 170 | * independent from the UIP */ |
170 | 171 | ||
171 | if (op) { | 172 | if (op) { |
172 | /* write: prepare values */ | 173 | /* write: prepare values */ |
173 | 174 | ||
174 | sec = t->tm_sec; | 175 | sec = t->tm_sec; |
175 | min = t->tm_min; | 176 | min = t->tm_min; |
176 | hour = t->tm_hour; | 177 | hour = t->tm_hour; |
177 | day = t->tm_mday; | 178 | day = t->tm_mday; |
178 | mon = t->tm_mon + 1; | 179 | mon = t->tm_mon + 1; |
179 | year = t->tm_year - atari_rtc_year_offset; | 180 | year = t->tm_year - atari_rtc_year_offset; |
180 | wday = t->tm_wday + (t->tm_wday >= 0); | 181 | wday = t->tm_wday + (t->tm_wday >= 0); |
181 | 182 | ||
182 | if (!(ctrl & RTC_24H)) { | 183 | if (!(ctrl & RTC_24H)) { |
183 | if (hour > 11) { | 184 | if (hour > 11) { |
184 | pm = 0x80; | 185 | pm = 0x80; |
185 | if (hour != 12) | 186 | if (hour != 12) |
186 | hour -= 12; | 187 | hour -= 12; |
187 | } | 188 | } |
188 | else if (hour == 0) | 189 | else if (hour == 0) |
189 | hour = 12; | 190 | hour = 12; |
190 | } | 191 | } |
191 | 192 | ||
192 | if (!(ctrl & RTC_DM_BINARY)) { | 193 | if (!(ctrl & RTC_DM_BINARY)) { |
193 | BIN_TO_BCD(sec); | 194 | BIN_TO_BCD(sec); |
194 | BIN_TO_BCD(min); | 195 | BIN_TO_BCD(min); |
195 | BIN_TO_BCD(hour); | 196 | BIN_TO_BCD(hour); |
196 | BIN_TO_BCD(day); | 197 | BIN_TO_BCD(day); |
197 | BIN_TO_BCD(mon); | 198 | BIN_TO_BCD(mon); |
198 | BIN_TO_BCD(year); | 199 | BIN_TO_BCD(year); |
199 | if (wday >= 0) BIN_TO_BCD(wday); | 200 | if (wday >= 0) BIN_TO_BCD(wday); |
200 | } | 201 | } |
201 | } | 202 | } |
202 | 203 | ||
203 | /* Reading/writing the clock registers is a bit critical due to | 204 | /* Reading/writing the clock registers is a bit critical due to |
204 | * the regular update cycle of the RTC. While an update is in | 205 | * the regular update cycle of the RTC. While an update is in |
205 | * progress, registers 0..9 shouldn't be touched. | 206 | * progress, registers 0..9 shouldn't be touched. |
206 | * The problem is solved like that: If an update is currently in | 207 | * The problem is solved like that: If an update is currently in |
207 | * progress (the UIP bit is set), the process sleeps for a while | 208 | * progress (the UIP bit is set), the process sleeps for a while |
208 | * (50ms). This really should be enough, since the update cycle | 209 | * (50ms). This really should be enough, since the update cycle |
209 | * normally needs 2 ms. | 210 | * normally needs 2 ms. |
210 | * If the UIP bit reads as 0, we have at least 244 usecs until the | 211 | * If the UIP bit reads as 0, we have at least 244 usecs until the |
211 | * update starts. This should be enough... But to be sure, | 212 | * update starts. This should be enough... But to be sure, |
212 | * additionally the RTC_SET bit is set to prevent an update cycle. | 213 | * additionally the RTC_SET bit is set to prevent an update cycle. |
213 | */ | 214 | */ |
214 | 215 | ||
215 | while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) | 216 | while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { |
216 | schedule_timeout_interruptible(HWCLK_POLL_INTERVAL); | 217 | if (in_atomic() || irqs_disabled()) |
218 | mdelay(1); | ||
219 | else | ||
220 | schedule_timeout_interruptible(HWCLK_POLL_INTERVAL); | ||
221 | } | ||
217 | 222 | ||
218 | local_irq_save(flags); | 223 | local_irq_save(flags); |
219 | RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); | 224 | RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); |
220 | if (!op) { | 225 | if (!op) { |
221 | sec = RTC_READ( RTC_SECONDS ); | 226 | sec = RTC_READ( RTC_SECONDS ); |
222 | min = RTC_READ( RTC_MINUTES ); | 227 | min = RTC_READ( RTC_MINUTES ); |
223 | hour = RTC_READ( RTC_HOURS ); | 228 | hour = RTC_READ( RTC_HOURS ); |
224 | day = RTC_READ( RTC_DAY_OF_MONTH ); | 229 | day = RTC_READ( RTC_DAY_OF_MONTH ); |
225 | mon = RTC_READ( RTC_MONTH ); | 230 | mon = RTC_READ( RTC_MONTH ); |
226 | year = RTC_READ( RTC_YEAR ); | 231 | year = RTC_READ( RTC_YEAR ); |
227 | wday = RTC_READ( RTC_DAY_OF_WEEK ); | 232 | wday = RTC_READ( RTC_DAY_OF_WEEK ); |
228 | } | 233 | } |
229 | else { | 234 | else { |
230 | RTC_WRITE( RTC_SECONDS, sec ); | 235 | RTC_WRITE( RTC_SECONDS, sec ); |
231 | RTC_WRITE( RTC_MINUTES, min ); | 236 | RTC_WRITE( RTC_MINUTES, min ); |
232 | RTC_WRITE( RTC_HOURS, hour + pm); | 237 | RTC_WRITE( RTC_HOURS, hour + pm); |
233 | RTC_WRITE( RTC_DAY_OF_MONTH, day ); | 238 | RTC_WRITE( RTC_DAY_OF_MONTH, day ); |
234 | RTC_WRITE( RTC_MONTH, mon ); | 239 | RTC_WRITE( RTC_MONTH, mon ); |
235 | RTC_WRITE( RTC_YEAR, year ); | 240 | RTC_WRITE( RTC_YEAR, year ); |
236 | if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); | 241 | if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); |
237 | } | 242 | } |
238 | RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); | 243 | RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); |
239 | local_irq_restore(flags); | 244 | local_irq_restore(flags); |
240 | 245 | ||
241 | if (!op) { | 246 | if (!op) { |
242 | /* read: adjust values */ | 247 | /* read: adjust values */ |
243 | 248 | ||
244 | if (hour & 0x80) { | 249 | if (hour & 0x80) { |
245 | hour &= ~0x80; | 250 | hour &= ~0x80; |
246 | pm = 1; | 251 | pm = 1; |
247 | } | 252 | } |
248 | 253 | ||
249 | if (!(ctrl & RTC_DM_BINARY)) { | 254 | if (!(ctrl & RTC_DM_BINARY)) { |
250 | BCD_TO_BIN(sec); | 255 | BCD_TO_BIN(sec); |
251 | BCD_TO_BIN(min); | 256 | BCD_TO_BIN(min); |
252 | BCD_TO_BIN(hour); | 257 | BCD_TO_BIN(hour); |
253 | BCD_TO_BIN(day); | 258 | BCD_TO_BIN(day); |
254 | BCD_TO_BIN(mon); | 259 | BCD_TO_BIN(mon); |
255 | BCD_TO_BIN(year); | 260 | BCD_TO_BIN(year); |
256 | BCD_TO_BIN(wday); | 261 | BCD_TO_BIN(wday); |
257 | } | 262 | } |
258 | 263 | ||
259 | if (!(ctrl & RTC_24H)) { | 264 | if (!(ctrl & RTC_24H)) { |
260 | if (!pm && hour == 12) | 265 | if (!pm && hour == 12) |
261 | hour = 0; | 266 | hour = 0; |
262 | else if (pm && hour != 12) | 267 | else if (pm && hour != 12) |
263 | hour += 12; | 268 | hour += 12; |
264 | } | 269 | } |
265 | 270 | ||
266 | t->tm_sec = sec; | 271 | t->tm_sec = sec; |
267 | t->tm_min = min; | 272 | t->tm_min = min; |
268 | t->tm_hour = hour; | 273 | t->tm_hour = hour; |
269 | t->tm_mday = day; | 274 | t->tm_mday = day; |
270 | t->tm_mon = mon - 1; | 275 | t->tm_mon = mon - 1; |
271 | t->tm_year = year + atari_rtc_year_offset; | 276 | t->tm_year = year + atari_rtc_year_offset; |
272 | t->tm_wday = wday - 1; | 277 | t->tm_wday = wday - 1; |
273 | } | 278 | } |
274 | 279 | ||
275 | return( 0 ); | 280 | return( 0 ); |
276 | } | 281 | } |
277 | 282 | ||
278 | 283 | ||
279 | int atari_mste_set_clock_mmss (unsigned long nowtime) | 284 | int atari_mste_set_clock_mmss (unsigned long nowtime) |
280 | { | 285 | { |
281 | short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; | 286 | short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; |
282 | struct MSTE_RTC val; | 287 | struct MSTE_RTC val; |
283 | unsigned char rtc_minutes; | 288 | unsigned char rtc_minutes; |
284 | 289 | ||
285 | mste_read(&val); | 290 | mste_read(&val); |
286 | rtc_minutes= val.min_ones + val.min_tens * 10; | 291 | rtc_minutes= val.min_ones + val.min_tens * 10; |
287 | if ((rtc_minutes < real_minutes | 292 | if ((rtc_minutes < real_minutes |
288 | ? real_minutes - rtc_minutes | 293 | ? real_minutes - rtc_minutes |
289 | : rtc_minutes - real_minutes) < 30) | 294 | : rtc_minutes - real_minutes) < 30) |
290 | { | 295 | { |
291 | val.sec_ones = real_seconds % 10; | 296 | val.sec_ones = real_seconds % 10; |
292 | val.sec_tens = real_seconds / 10; | 297 | val.sec_tens = real_seconds / 10; |
293 | val.min_ones = real_minutes % 10; | 298 | val.min_ones = real_minutes % 10; |
294 | val.min_tens = real_minutes / 10; | 299 | val.min_tens = real_minutes / 10; |
295 | mste_write(&val); | 300 | mste_write(&val); |
296 | } | 301 | } |
297 | else | 302 | else |
298 | return -1; | 303 | return -1; |
299 | return 0; | 304 | return 0; |
300 | } | 305 | } |
301 | 306 | ||
302 | int atari_tt_set_clock_mmss (unsigned long nowtime) | 307 | int atari_tt_set_clock_mmss (unsigned long nowtime) |
303 | { | 308 | { |
304 | int retval = 0; | 309 | int retval = 0; |
305 | short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; | 310 | short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; |
306 | unsigned char save_control, save_freq_select, rtc_minutes; | 311 | unsigned char save_control, save_freq_select, rtc_minutes; |
307 | 312 | ||
308 | save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ | 313 | save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ |
309 | RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); | 314 | RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); |
310 | 315 | ||
311 | save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ | 316 | save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ |
312 | RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); | 317 | RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); |
313 | 318 | ||
314 | rtc_minutes = RTC_READ (RTC_MINUTES); | 319 | rtc_minutes = RTC_READ (RTC_MINUTES); |
315 | if (!(save_control & RTC_DM_BINARY)) | 320 | if (!(save_control & RTC_DM_BINARY)) |
316 | BCD_TO_BIN (rtc_minutes); | 321 | BCD_TO_BIN (rtc_minutes); |
317 | 322 | ||
318 | /* Since we're only adjusting minutes and seconds, don't interfere | 323 | /* Since we're only adjusting minutes and seconds, don't interfere |
319 | with hour overflow. This avoids messing with unknown time zones | 324 | with hour overflow. This avoids messing with unknown time zones |
320 | but requires your RTC not to be off by more than 30 minutes. */ | 325 | but requires your RTC not to be off by more than 30 minutes. */ |
321 | if ((rtc_minutes < real_minutes | 326 | if ((rtc_minutes < real_minutes |
322 | ? real_minutes - rtc_minutes | 327 | ? real_minutes - rtc_minutes |
323 | : rtc_minutes - real_minutes) < 30) | 328 | : rtc_minutes - real_minutes) < 30) |
324 | { | 329 | { |
325 | if (!(save_control & RTC_DM_BINARY)) | 330 | if (!(save_control & RTC_DM_BINARY)) |
326 | { | 331 | { |
327 | BIN_TO_BCD (real_seconds); | 332 | BIN_TO_BCD (real_seconds); |
328 | BIN_TO_BCD (real_minutes); | 333 | BIN_TO_BCD (real_minutes); |
329 | } | 334 | } |
330 | RTC_WRITE (RTC_SECONDS, real_seconds); | 335 | RTC_WRITE (RTC_SECONDS, real_seconds); |
331 | RTC_WRITE (RTC_MINUTES, real_minutes); | 336 | RTC_WRITE (RTC_MINUTES, real_minutes); |
332 | } | 337 | } |
333 | else | 338 | else |
334 | retval = -1; | 339 | retval = -1; |
335 | 340 | ||
336 | RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); | 341 | RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); |
337 | RTC_WRITE (RTC_CONTROL, save_control); | 342 | RTC_WRITE (RTC_CONTROL, save_control); |
338 | return retval; | 343 | return retval; |
339 | } | 344 | } |
340 | 345 | ||
341 | /* | 346 | /* |
342 | * Local variables: | 347 | * Local variables: |
343 | * c-indent-level: 4 | 348 | * c-indent-level: 4 |
344 | * tab-width: 8 | 349 | * tab-width: 8 |
345 | * End: | 350 | * End: |
346 | */ | 351 | */ |
347 | 352 |
arch/m68k/kernel/ints.c
1 | /* | 1 | /* |
2 | * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code | 2 | * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code |
3 | * | 3 | * |
4 | * This file is subject to the terms and conditions of the GNU General Public | 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 | 5 | * License. See the file COPYING in the main directory of this archive |
6 | * for more details. | 6 | * for more details. |
7 | * | 7 | * |
8 | * 07/03/96: Timer initialization, and thus mach_sched_init(), | 8 | * 07/03/96: Timer initialization, and thus mach_sched_init(), |
9 | * removed from request_irq() and moved to init_time(). | 9 | * removed from request_irq() and moved to init_time(). |
10 | * We should therefore consider renaming our add_isr() and | 10 | * We should therefore consider renaming our add_isr() and |
11 | * remove_isr() to request_irq() and free_irq() | 11 | * remove_isr() to request_irq() and free_irq() |
12 | * respectively, so they are compliant with the other | 12 | * respectively, so they are compliant with the other |
13 | * architectures. /Jes | 13 | * architectures. /Jes |
14 | * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls. | 14 | * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls. |
15 | * Removed irq list support, if any machine needs an irq server | 15 | * Removed irq list support, if any machine needs an irq server |
16 | * it must implement this itself (as it's already done), instead | 16 | * it must implement this itself (as it's already done), instead |
17 | * only default handler are used with mach_default_handler. | 17 | * only default handler are used with mach_default_handler. |
18 | * request_irq got some flags different from other architectures: | 18 | * request_irq got some flags different from other architectures: |
19 | * - IRQ_FLG_REPLACE : Replace an existing handler (the default one | 19 | * - IRQ_FLG_REPLACE : Replace an existing handler (the default one |
20 | * can be replaced without this flag) | 20 | * can be replaced without this flag) |
21 | * - IRQ_FLG_LOCK : handler can't be replaced | 21 | * - IRQ_FLG_LOCK : handler can't be replaced |
22 | * There are other machine depending flags, see there | 22 | * There are other machine depending flags, see there |
23 | * If you want to replace a default handler you should know what | 23 | * If you want to replace a default handler you should know what |
24 | * you're doing, since it might handle different other irq sources | 24 | * you're doing, since it might handle different other irq sources |
25 | * which must be served /Roman Zippel | 25 | * which must be served /Roman Zippel |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/types.h> | 29 | #include <linux/types.h> |
30 | #include <linux/sched.h> | 30 | #include <linux/sched.h> |
31 | #include <linux/kernel_stat.h> | 31 | #include <linux/kernel_stat.h> |
32 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | 34 | ||
35 | #include <asm/setup.h> | 35 | #include <asm/setup.h> |
36 | #include <asm/system.h> | 36 | #include <asm/system.h> |
37 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
38 | #include <asm/traps.h> | 38 | #include <asm/traps.h> |
39 | #include <asm/page.h> | 39 | #include <asm/page.h> |
40 | #include <asm/machdep.h> | 40 | #include <asm/machdep.h> |
41 | #include <asm/cacheflush.h> | 41 | #include <asm/cacheflush.h> |
42 | #include <asm/irq_regs.h> | 42 | #include <asm/irq_regs.h> |
43 | 43 | ||
44 | #ifdef CONFIG_Q40 | 44 | #ifdef CONFIG_Q40 |
45 | #include <asm/q40ints.h> | 45 | #include <asm/q40ints.h> |
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | extern u32 auto_irqhandler_fixup[]; | 48 | extern u32 auto_irqhandler_fixup[]; |
49 | extern u32 user_irqhandler_fixup[]; | 49 | extern u32 user_irqhandler_fixup[]; |
50 | extern u16 user_irqvec_fixup[]; | 50 | extern u16 user_irqvec_fixup[]; |
51 | 51 | ||
52 | /* table for system interrupt handlers */ | 52 | /* table for system interrupt handlers */ |
53 | static struct irq_node *irq_list[NR_IRQS]; | 53 | static struct irq_node *irq_list[NR_IRQS]; |
54 | static struct irq_controller *irq_controller[NR_IRQS]; | 54 | static struct irq_controller *irq_controller[NR_IRQS]; |
55 | static int irq_depth[NR_IRQS]; | 55 | static int irq_depth[NR_IRQS]; |
56 | 56 | ||
57 | static int m68k_first_user_vec; | 57 | static int m68k_first_user_vec; |
58 | 58 | ||
59 | static struct irq_controller auto_irq_controller = { | 59 | static struct irq_controller auto_irq_controller = { |
60 | .name = "auto", | 60 | .name = "auto", |
61 | .lock = SPIN_LOCK_UNLOCKED, | 61 | .lock = SPIN_LOCK_UNLOCKED, |
62 | .startup = m68k_irq_startup, | 62 | .startup = m68k_irq_startup, |
63 | .shutdown = m68k_irq_shutdown, | 63 | .shutdown = m68k_irq_shutdown, |
64 | }; | 64 | }; |
65 | 65 | ||
66 | static struct irq_controller user_irq_controller = { | 66 | static struct irq_controller user_irq_controller = { |
67 | .name = "user", | 67 | .name = "user", |
68 | .lock = SPIN_LOCK_UNLOCKED, | 68 | .lock = SPIN_LOCK_UNLOCKED, |
69 | .startup = m68k_irq_startup, | 69 | .startup = m68k_irq_startup, |
70 | .shutdown = m68k_irq_shutdown, | 70 | .shutdown = m68k_irq_shutdown, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | #define NUM_IRQ_NODES 100 | 73 | #define NUM_IRQ_NODES 100 |
74 | static irq_node_t nodes[NUM_IRQ_NODES]; | 74 | static irq_node_t nodes[NUM_IRQ_NODES]; |
75 | 75 | ||
76 | /* | 76 | /* |
77 | * void init_IRQ(void) | 77 | * void init_IRQ(void) |
78 | * | 78 | * |
79 | * Parameters: None | 79 | * Parameters: None |
80 | * | 80 | * |
81 | * Returns: Nothing | 81 | * Returns: Nothing |
82 | * | 82 | * |
83 | * This function should be called during kernel startup to initialize | 83 | * This function should be called during kernel startup to initialize |
84 | * the IRQ handling routines. | 84 | * the IRQ handling routines. |
85 | */ | 85 | */ |
86 | 86 | ||
87 | void __init init_IRQ(void) | 87 | void __init init_IRQ(void) |
88 | { | 88 | { |
89 | int i; | 89 | int i; |
90 | 90 | ||
91 | /* assembly irq entry code relies on this... */ | 91 | /* assembly irq entry code relies on this... */ |
92 | if (HARDIRQ_MASK != 0x00ff0000) { | 92 | if (HARDIRQ_MASK != 0x00ff0000) { |
93 | extern void hardirq_mask_is_broken(void); | 93 | extern void hardirq_mask_is_broken(void); |
94 | hardirq_mask_is_broken(); | 94 | hardirq_mask_is_broken(); |
95 | } | 95 | } |
96 | 96 | ||
97 | for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) | 97 | for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) |
98 | irq_controller[i] = &auto_irq_controller; | 98 | irq_controller[i] = &auto_irq_controller; |
99 | 99 | ||
100 | mach_init_IRQ(); | 100 | mach_init_IRQ(); |
101 | } | 101 | } |
102 | 102 | ||
103 | /** | 103 | /** |
104 | * m68k_setup_auto_interrupt | 104 | * m68k_setup_auto_interrupt |
105 | * @handler: called from auto vector interrupts | 105 | * @handler: called from auto vector interrupts |
106 | * | 106 | * |
107 | * setup the handler to be called from auto vector interrupts instead of the | 107 | * setup the handler to be called from auto vector interrupts instead of the |
108 | * standard __m68k_handle_int(), it will be called with irq numbers in the range | 108 | * standard __m68k_handle_int(), it will be called with irq numbers in the range |
109 | * from IRQ_AUTO_1 - IRQ_AUTO_7. | 109 | * from IRQ_AUTO_1 - IRQ_AUTO_7. |
110 | */ | 110 | */ |
111 | void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) | 111 | void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) |
112 | { | 112 | { |
113 | if (handler) | 113 | if (handler) |
114 | *auto_irqhandler_fixup = (u32)handler; | 114 | *auto_irqhandler_fixup = (u32)handler; |
115 | flush_icache(); | 115 | flush_icache(); |
116 | } | 116 | } |
117 | 117 | ||
118 | /** | 118 | /** |
119 | * m68k_setup_user_interrupt | 119 | * m68k_setup_user_interrupt |
120 | * @vec: first user vector interrupt to handle | 120 | * @vec: first user vector interrupt to handle |
121 | * @cnt: number of active user vector interrupts | 121 | * @cnt: number of active user vector interrupts |
122 | * @handler: called from user vector interrupts | 122 | * @handler: called from user vector interrupts |
123 | * | 123 | * |
124 | * setup user vector interrupts, this includes activating the specified range | 124 | * setup user vector interrupts, this includes activating the specified range |
125 | * of interrupts, only then these interrupts can be requested (note: this is | 125 | * of interrupts, only then these interrupts can be requested (note: this is |
126 | * different from auto vector interrupts). An optional handler can be installed | 126 | * different from auto vector interrupts). An optional handler can be installed |
127 | * to be called instead of the default __m68k_handle_int(), it will be called | 127 | * to be called instead of the default __m68k_handle_int(), it will be called |
128 | * with irq numbers starting from IRQ_USER. | 128 | * with irq numbers starting from IRQ_USER. |
129 | */ | 129 | */ |
130 | void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, | 130 | void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, |
131 | void (*handler)(unsigned int, struct pt_regs *)) | 131 | void (*handler)(unsigned int, struct pt_regs *)) |
132 | { | 132 | { |
133 | int i; | 133 | int i; |
134 | 134 | ||
135 | BUG_ON(IRQ_USER + cnt >= NR_IRQS); | ||
135 | m68k_first_user_vec = vec; | 136 | m68k_first_user_vec = vec; |
136 | for (i = 0; i < cnt; i++) | 137 | for (i = 0; i < cnt; i++) |
137 | irq_controller[IRQ_USER + i] = &user_irq_controller; | 138 | irq_controller[IRQ_USER + i] = &user_irq_controller; |
138 | *user_irqvec_fixup = vec - IRQ_USER; | 139 | *user_irqvec_fixup = vec - IRQ_USER; |
139 | if (handler) | 140 | if (handler) |
140 | *user_irqhandler_fixup = (u32)handler; | 141 | *user_irqhandler_fixup = (u32)handler; |
141 | flush_icache(); | 142 | flush_icache(); |
142 | } | 143 | } |
143 | 144 | ||
144 | /** | 145 | /** |
145 | * m68k_setup_irq_controller | 146 | * m68k_setup_irq_controller |
146 | * @contr: irq controller which controls specified irq | 147 | * @contr: irq controller which controls specified irq |
147 | * @irq: first irq to be managed by the controller | 148 | * @irq: first irq to be managed by the controller |
148 | * | 149 | * |
149 | * Change the controller for the specified range of irq, which will be used to | 150 | * Change the controller for the specified range of irq, which will be used to |
150 | * manage these irq. auto/user irq already have a default controller, which can | 151 | * manage these irq. auto/user irq already have a default controller, which can |
151 | * be changed as well, but the controller probably should use m68k_irq_startup/ | 152 | * be changed as well, but the controller probably should use m68k_irq_startup/ |
152 | * m68k_irq_shutdown. | 153 | * m68k_irq_shutdown. |
153 | */ | 154 | */ |
154 | void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq, | 155 | void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq, |
155 | unsigned int cnt) | 156 | unsigned int cnt) |
156 | { | 157 | { |
157 | int i; | 158 | int i; |
158 | 159 | ||
159 | for (i = 0; i < cnt; i++) | 160 | for (i = 0; i < cnt; i++) |
160 | irq_controller[irq + i] = contr; | 161 | irq_controller[irq + i] = contr; |
161 | } | 162 | } |
162 | 163 | ||
163 | irq_node_t *new_irq_node(void) | 164 | irq_node_t *new_irq_node(void) |
164 | { | 165 | { |
165 | irq_node_t *node; | 166 | irq_node_t *node; |
166 | short i; | 167 | short i; |
167 | 168 | ||
168 | for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { | 169 | for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { |
169 | if (!node->handler) { | 170 | if (!node->handler) { |
170 | memset(node, 0, sizeof(*node)); | 171 | memset(node, 0, sizeof(*node)); |
171 | return node; | 172 | return node; |
172 | } | 173 | } |
173 | } | 174 | } |
174 | 175 | ||
175 | printk ("new_irq_node: out of nodes\n"); | 176 | printk ("new_irq_node: out of nodes\n"); |
176 | return NULL; | 177 | return NULL; |
177 | } | 178 | } |
178 | 179 | ||
179 | int setup_irq(unsigned int irq, struct irq_node *node) | 180 | int setup_irq(unsigned int irq, struct irq_node *node) |
180 | { | 181 | { |
181 | struct irq_controller *contr; | 182 | struct irq_controller *contr; |
182 | struct irq_node **prev; | 183 | struct irq_node **prev; |
183 | unsigned long flags; | 184 | unsigned long flags; |
184 | 185 | ||
185 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | 186 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
186 | printk("%s: Incorrect IRQ %d from %s\n", | 187 | printk("%s: Incorrect IRQ %d from %s\n", |
187 | __FUNCTION__, irq, node->devname); | 188 | __FUNCTION__, irq, node->devname); |
188 | return -ENXIO; | 189 | return -ENXIO; |
189 | } | 190 | } |
190 | 191 | ||
191 | spin_lock_irqsave(&contr->lock, flags); | 192 | spin_lock_irqsave(&contr->lock, flags); |
192 | 193 | ||
193 | prev = irq_list + irq; | 194 | prev = irq_list + irq; |
194 | if (*prev) { | 195 | if (*prev) { |
195 | /* Can't share interrupts unless both agree to */ | 196 | /* Can't share interrupts unless both agree to */ |
196 | if (!((*prev)->flags & node->flags & IRQF_SHARED)) { | 197 | if (!((*prev)->flags & node->flags & IRQF_SHARED)) { |
197 | spin_unlock_irqrestore(&contr->lock, flags); | 198 | spin_unlock_irqrestore(&contr->lock, flags); |
198 | return -EBUSY; | 199 | return -EBUSY; |
199 | } | 200 | } |
200 | while (*prev) | 201 | while (*prev) |
201 | prev = &(*prev)->next; | 202 | prev = &(*prev)->next; |
202 | } | 203 | } |
203 | 204 | ||
204 | if (!irq_list[irq]) { | 205 | if (!irq_list[irq]) { |
205 | if (contr->startup) | 206 | if (contr->startup) |
206 | contr->startup(irq); | 207 | contr->startup(irq); |
207 | else | 208 | else |
208 | contr->enable(irq); | 209 | contr->enable(irq); |
209 | } | 210 | } |
210 | node->next = NULL; | 211 | node->next = NULL; |
211 | *prev = node; | 212 | *prev = node; |
212 | 213 | ||
213 | spin_unlock_irqrestore(&contr->lock, flags); | 214 | spin_unlock_irqrestore(&contr->lock, flags); |
214 | 215 | ||
215 | return 0; | 216 | return 0; |
216 | } | 217 | } |
217 | 218 | ||
218 | int request_irq(unsigned int irq, | 219 | int request_irq(unsigned int irq, |
219 | irq_handler_t handler, | 220 | irq_handler_t handler, |
220 | unsigned long flags, const char *devname, void *dev_id) | 221 | unsigned long flags, const char *devname, void *dev_id) |
221 | { | 222 | { |
222 | struct irq_node *node; | 223 | struct irq_node *node; |
223 | int res; | 224 | int res; |
224 | 225 | ||
225 | node = new_irq_node(); | 226 | node = new_irq_node(); |
226 | if (!node) | 227 | if (!node) |
227 | return -ENOMEM; | 228 | return -ENOMEM; |
228 | 229 | ||
229 | node->handler = handler; | 230 | node->handler = handler; |
230 | node->flags = flags; | 231 | node->flags = flags; |
231 | node->dev_id = dev_id; | 232 | node->dev_id = dev_id; |
232 | node->devname = devname; | 233 | node->devname = devname; |
233 | 234 | ||
234 | res = setup_irq(irq, node); | 235 | res = setup_irq(irq, node); |
235 | if (res) | 236 | if (res) |
236 | node->handler = NULL; | 237 | node->handler = NULL; |
237 | 238 | ||
238 | return res; | 239 | return res; |
239 | } | 240 | } |
240 | 241 | ||
241 | EXPORT_SYMBOL(request_irq); | 242 | EXPORT_SYMBOL(request_irq); |
242 | 243 | ||
243 | void free_irq(unsigned int irq, void *dev_id) | 244 | void free_irq(unsigned int irq, void *dev_id) |
244 | { | 245 | { |
245 | struct irq_controller *contr; | 246 | struct irq_controller *contr; |
246 | struct irq_node **p, *node; | 247 | struct irq_node **p, *node; |
247 | unsigned long flags; | 248 | unsigned long flags; |
248 | 249 | ||
249 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | 250 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
250 | printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); | 251 | printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); |
251 | return; | 252 | return; |
252 | } | 253 | } |
253 | 254 | ||
254 | spin_lock_irqsave(&contr->lock, flags); | 255 | spin_lock_irqsave(&contr->lock, flags); |
255 | 256 | ||
256 | p = irq_list + irq; | 257 | p = irq_list + irq; |
257 | while ((node = *p)) { | 258 | while ((node = *p)) { |
258 | if (node->dev_id == dev_id) | 259 | if (node->dev_id == dev_id) |
259 | break; | 260 | break; |
260 | p = &node->next; | 261 | p = &node->next; |
261 | } | 262 | } |
262 | 263 | ||
263 | if (node) { | 264 | if (node) { |
264 | *p = node->next; | 265 | *p = node->next; |
265 | node->handler = NULL; | 266 | node->handler = NULL; |
266 | } else | 267 | } else |
267 | printk("%s: Removing probably wrong IRQ %d\n", | 268 | printk("%s: Removing probably wrong IRQ %d\n", |
268 | __FUNCTION__, irq); | 269 | __FUNCTION__, irq); |
269 | 270 | ||
270 | if (!irq_list[irq]) { | 271 | if (!irq_list[irq]) { |
271 | if (contr->shutdown) | 272 | if (contr->shutdown) |
272 | contr->shutdown(irq); | 273 | contr->shutdown(irq); |
273 | else | 274 | else |
274 | contr->disable(irq); | 275 | contr->disable(irq); |
275 | } | 276 | } |
276 | 277 | ||
277 | spin_unlock_irqrestore(&contr->lock, flags); | 278 | spin_unlock_irqrestore(&contr->lock, flags); |
278 | } | 279 | } |
279 | 280 | ||
280 | EXPORT_SYMBOL(free_irq); | 281 | EXPORT_SYMBOL(free_irq); |
281 | 282 | ||
282 | void enable_irq(unsigned int irq) | 283 | void enable_irq(unsigned int irq) |
283 | { | 284 | { |
284 | struct irq_controller *contr; | 285 | struct irq_controller *contr; |
285 | unsigned long flags; | 286 | unsigned long flags; |
286 | 287 | ||
287 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | 288 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
288 | printk("%s: Incorrect IRQ %d\n", | 289 | printk("%s: Incorrect IRQ %d\n", |
289 | __FUNCTION__, irq); | 290 | __FUNCTION__, irq); |
290 | return; | 291 | return; |
291 | } | 292 | } |
292 | 293 | ||
293 | spin_lock_irqsave(&contr->lock, flags); | 294 | spin_lock_irqsave(&contr->lock, flags); |
294 | if (irq_depth[irq]) { | 295 | if (irq_depth[irq]) { |
295 | if (!--irq_depth[irq]) { | 296 | if (!--irq_depth[irq]) { |
296 | if (contr->enable) | 297 | if (contr->enable) |
297 | contr->enable(irq); | 298 | contr->enable(irq); |
298 | } | 299 | } |
299 | } else | 300 | } else |
300 | WARN_ON(1); | 301 | WARN_ON(1); |
301 | spin_unlock_irqrestore(&contr->lock, flags); | 302 | spin_unlock_irqrestore(&contr->lock, flags); |
302 | } | 303 | } |
303 | 304 | ||
304 | EXPORT_SYMBOL(enable_irq); | 305 | EXPORT_SYMBOL(enable_irq); |
305 | 306 | ||
306 | void disable_irq(unsigned int irq) | 307 | void disable_irq(unsigned int irq) |
307 | { | 308 | { |
308 | struct irq_controller *contr; | 309 | struct irq_controller *contr; |
309 | unsigned long flags; | 310 | unsigned long flags; |
310 | 311 | ||
311 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | 312 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
312 | printk("%s: Incorrect IRQ %d\n", | 313 | printk("%s: Incorrect IRQ %d\n", |
313 | __FUNCTION__, irq); | 314 | __FUNCTION__, irq); |
314 | return; | 315 | return; |
315 | } | 316 | } |
316 | 317 | ||
317 | spin_lock_irqsave(&contr->lock, flags); | 318 | spin_lock_irqsave(&contr->lock, flags); |
318 | if (!irq_depth[irq]++) { | 319 | if (!irq_depth[irq]++) { |
319 | if (contr->disable) | 320 | if (contr->disable) |
320 | contr->disable(irq); | 321 | contr->disable(irq); |
321 | } | 322 | } |
322 | spin_unlock_irqrestore(&contr->lock, flags); | 323 | spin_unlock_irqrestore(&contr->lock, flags); |
323 | } | 324 | } |
324 | 325 | ||
325 | EXPORT_SYMBOL(disable_irq); | 326 | EXPORT_SYMBOL(disable_irq); |
326 | 327 | ||
327 | int m68k_irq_startup(unsigned int irq) | 328 | int m68k_irq_startup(unsigned int irq) |
328 | { | 329 | { |
329 | if (irq <= IRQ_AUTO_7) | 330 | if (irq <= IRQ_AUTO_7) |
330 | vectors[VEC_SPUR + irq] = auto_inthandler; | 331 | vectors[VEC_SPUR + irq] = auto_inthandler; |
331 | else | 332 | else |
332 | vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; | 333 | vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; |
333 | return 0; | 334 | return 0; |
334 | } | 335 | } |
335 | 336 | ||
336 | void m68k_irq_shutdown(unsigned int irq) | 337 | void m68k_irq_shutdown(unsigned int irq) |
337 | { | 338 | { |
338 | if (irq <= IRQ_AUTO_7) | 339 | if (irq <= IRQ_AUTO_7) |
339 | vectors[VEC_SPUR + irq] = bad_inthandler; | 340 | vectors[VEC_SPUR + irq] = bad_inthandler; |
340 | else | 341 | else |
341 | vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; | 342 | vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; |
342 | } | 343 | } |
343 | 344 | ||
344 | 345 | ||
345 | /* | 346 | /* |
346 | * Do we need these probe functions on the m68k? | 347 | * Do we need these probe functions on the m68k? |
347 | * | 348 | * |
348 | * ... may be useful with ISA devices | 349 | * ... may be useful with ISA devices |
349 | */ | 350 | */ |
350 | unsigned long probe_irq_on (void) | 351 | unsigned long probe_irq_on (void) |
351 | { | 352 | { |
352 | #ifdef CONFIG_Q40 | 353 | #ifdef CONFIG_Q40 |
353 | if (MACH_IS_Q40) | 354 | if (MACH_IS_Q40) |
354 | return q40_probe_irq_on(); | 355 | return q40_probe_irq_on(); |
355 | #endif | 356 | #endif |
356 | return 0; | 357 | return 0; |
357 | } | 358 | } |
358 | 359 | ||
359 | EXPORT_SYMBOL(probe_irq_on); | 360 | EXPORT_SYMBOL(probe_irq_on); |
360 | 361 | ||
361 | int probe_irq_off (unsigned long irqs) | 362 | int probe_irq_off (unsigned long irqs) |
362 | { | 363 | { |
363 | #ifdef CONFIG_Q40 | 364 | #ifdef CONFIG_Q40 |
364 | if (MACH_IS_Q40) | 365 | if (MACH_IS_Q40) |
365 | return q40_probe_irq_off(irqs); | 366 | return q40_probe_irq_off(irqs); |
366 | #endif | 367 | #endif |
367 | return 0; | 368 | return 0; |
368 | } | 369 | } |
369 | 370 | ||
370 | EXPORT_SYMBOL(probe_irq_off); | 371 | EXPORT_SYMBOL(probe_irq_off); |
371 | 372 | ||
372 | unsigned int irq_canonicalize(unsigned int irq) | 373 | unsigned int irq_canonicalize(unsigned int irq) |
373 | { | 374 | { |
374 | #ifdef CONFIG_Q40 | 375 | #ifdef CONFIG_Q40 |
375 | if (MACH_IS_Q40 && irq == 11) | 376 | if (MACH_IS_Q40 && irq == 11) |
376 | irq = 10; | 377 | irq = 10; |
377 | #endif | 378 | #endif |
378 | return irq; | 379 | return irq; |
379 | } | 380 | } |
380 | 381 | ||
381 | EXPORT_SYMBOL(irq_canonicalize); | 382 | EXPORT_SYMBOL(irq_canonicalize); |
382 | 383 | ||
383 | asmlinkage void m68k_handle_int(unsigned int irq) | 384 | asmlinkage void m68k_handle_int(unsigned int irq) |
384 | { | 385 | { |
385 | struct irq_node *node; | 386 | struct irq_node *node; |
386 | kstat_cpu(0).irqs[irq]++; | 387 | kstat_cpu(0).irqs[irq]++; |
387 | node = irq_list[irq]; | 388 | node = irq_list[irq]; |
388 | do { | 389 | do { |
389 | node->handler(irq, node->dev_id); | 390 | node->handler(irq, node->dev_id); |
390 | node = node->next; | 391 | node = node->next; |
391 | } while (node); | 392 | } while (node); |
392 | } | 393 | } |
393 | 394 | ||
394 | asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs) | 395 | asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs) |
395 | { | 396 | { |
396 | struct pt_regs *old_regs; | 397 | struct pt_regs *old_regs; |
397 | old_regs = set_irq_regs(regs); | 398 | old_regs = set_irq_regs(regs); |
398 | m68k_handle_int(irq); | 399 | m68k_handle_int(irq); |
399 | set_irq_regs(old_regs); | 400 | set_irq_regs(old_regs); |
400 | } | 401 | } |
401 | 402 | ||
402 | asmlinkage void handle_badint(struct pt_regs *regs) | 403 | asmlinkage void handle_badint(struct pt_regs *regs) |
403 | { | 404 | { |
404 | kstat_cpu(0).irqs[0]++; | 405 | kstat_cpu(0).irqs[0]++; |
405 | printk("unexpected interrupt from %u\n", regs->vector); | 406 | printk("unexpected interrupt from %u\n", regs->vector); |
406 | } | 407 | } |
407 | 408 | ||
408 | int show_interrupts(struct seq_file *p, void *v) | 409 | int show_interrupts(struct seq_file *p, void *v) |
409 | { | 410 | { |
410 | struct irq_controller *contr; | 411 | struct irq_controller *contr; |
411 | struct irq_node *node; | 412 | struct irq_node *node; |
412 | int i = *(loff_t *) v; | 413 | int i = *(loff_t *) v; |
413 | 414 | ||
414 | /* autovector interrupts */ | 415 | /* autovector interrupts */ |
415 | if (irq_list[i]) { | 416 | if (irq_list[i]) { |
416 | contr = irq_controller[i]; | 417 | contr = irq_controller[i]; |
417 | node = irq_list[i]; | 418 | node = irq_list[i]; |
418 | seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); | 419 | seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); |
419 | while ((node = node->next)) | 420 | while ((node = node->next)) |
420 | seq_printf(p, ", %s", node->devname); | 421 | seq_printf(p, ", %s", node->devname); |
421 | seq_puts(p, "\n"); | 422 | seq_puts(p, "\n"); |
422 | } | 423 | } |
423 | return 0; | 424 | return 0; |
424 | } | 425 | } |
425 | 426 | ||
426 | void init_irq_proc(void) | 427 | void init_irq_proc(void) |
427 | { | 428 | { |
428 | /* Insert /proc/irq driver here */ | 429 | /* Insert /proc/irq driver here */ |
429 | } | 430 | } |
430 | 431 | ||
431 | 432 |