diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/m68k/atari |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/m68k/atari')
-rw-r--r-- | arch/m68k/atari/Makefile | 10 | ||||
-rw-r--r-- | arch/m68k/atari/ataints.c | 648 | ||||
-rw-r--r-- | arch/m68k/atari/atari_ksyms.c | 35 | ||||
-rw-r--r-- | arch/m68k/atari/atasound.c | 109 | ||||
-rw-r--r-- | arch/m68k/atari/atasound.h | 33 | ||||
-rw-r--r-- | arch/m68k/atari/config.c | 726 | ||||
-rw-r--r-- | arch/m68k/atari/debug.c | 347 | ||||
-rw-r--r-- | arch/m68k/atari/hades-pci.c | 444 | ||||
-rw-r--r-- | arch/m68k/atari/stdma.c | 196 | ||||
-rw-r--r-- | arch/m68k/atari/stram.c | 1247 | ||||
-rw-r--r-- | arch/m68k/atari/time.c | 348 |
11 files changed, 4143 insertions, 0 deletions
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile new file mode 100644 index 000000000000..8cb6236b39db --- /dev/null +++ b/arch/m68k/atari/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for Linux arch/m68k/atari source directory | ||
3 | # | ||
4 | |||
5 | obj-y := config.o time.o debug.o ataints.o stdma.o \ | ||
6 | atasound.o stram.o atari_ksyms.o | ||
7 | |||
8 | ifeq ($(CONFIG_PCI),y) | ||
9 | obj-$(CONFIG_HADES) += hades-pci.o | ||
10 | endif | ||
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c new file mode 100644 index 000000000000..076f47917842 --- /dev/null +++ b/arch/m68k/atari/ataints.c | |||
@@ -0,0 +1,648 @@ | |||
1 | /* | ||
2 | * arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code | ||
3 | * | ||
4 | * 5/2/94 Roman Hodek: | ||
5 | * Added support for TT interrupts; setup for TT SCU (may someone has | ||
6 | * twiddled there and we won't get the right interrupts :-() | ||
7 | * | ||
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 | ||
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 | ||
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 | ||
14 | * call trap() instead of inthandler(). This must be changed here, too. | ||
15 | * | ||
16 | * 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>: | ||
17 | * Corrected a bug in atari_add_isr() which rejected all SCC | ||
18 | * interrupt sources if there were no TT MFP! | ||
19 | * | ||
20 | * 12/13/95: New interface functions atari_level_triggered_int() and | ||
21 | * atari_register_vme_int() as support for level triggered VME interrupts. | ||
22 | * | ||
23 | * 02/12/96: (Roman) | ||
24 | * Total rewrite of Atari interrupt handling, for new scheme see comments | ||
25 | * below. | ||
26 | * | ||
27 | * 1996-09-03 lars brinkhoff <f93labr@dd.chalmers.se>: | ||
28 | * Added new function atari_unregister_vme_int(), and | ||
29 | * modified atari_register_vme_int() as well as IS_VALID_INTNO() | ||
30 | * to work with it. | ||
31 | * | ||
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 | ||
34 | * for more details. | ||
35 | * | ||
36 | */ | ||
37 | |||
38 | #include <linux/types.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/kernel_stat.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/seq_file.h> | ||
43 | |||
44 | #include <asm/system.h> | ||
45 | #include <asm/traps.h> | ||
46 | |||
47 | #include <asm/atarihw.h> | ||
48 | #include <asm/atariints.h> | ||
49 | #include <asm/atari_stdma.h> | ||
50 | #include <asm/irq.h> | ||
51 | #include <asm/entry.h> | ||
52 | |||
53 | |||
54 | /* | ||
55 | * Atari interrupt handling scheme: | ||
56 | * -------------------------------- | ||
57 | * | ||
58 | * All interrupt source have an internal number (defined in | ||
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 | ||
61 | * be allocated by atari_register_vme_int(). | ||
62 | * | ||
63 | * Each interrupt can be of three types: | ||
64 | * | ||
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. | ||
67 | * But it is currently possible only for MFP ints, since only the MFP | ||
68 | * offers an easy way to mask interrupts. | ||
69 | * | ||
70 | * - FAST: The handler runs with all interrupts disabled. This should be used | ||
71 | * only for really fast handlers, that just do actions immediately | ||
72 | * necessary, and let the rest do a bottom half or task queue. | ||
73 | * | ||
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 | ||
76 | * which should be slow, but are not from a MFP. | ||
77 | * | ||
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 | ||
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 | ||
82 | * second handler is registered. | ||
83 | * | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 :-( | ||
96 | * | ||
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 | ||
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 | ||
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 | ||
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. | ||
105 | */ | ||
106 | |||
107 | |||
108 | #define NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES) | ||
109 | |||
110 | typedef void (*asm_irq_handler)(void); | ||
111 | |||
112 | struct irqhandler { | ||
113 | irqreturn_t (*handler)(int, void *, struct pt_regs *); | ||
114 | void *dev_id; | ||
115 | }; | ||
116 | |||
117 | struct irqparam { | ||
118 | unsigned long flags; | ||
119 | const char *devname; | ||
120 | }; | ||
121 | |||
122 | /* | ||
123 | * Array with irq's and their parameter data. This array is accessed from low | ||
124 | * level assembler code, so an element size of 8 allows usage of index scaling | ||
125 | * addressing mode. | ||
126 | */ | ||
127 | static struct irqhandler irq_handler[NUM_INT_SOURCES]; | ||
128 | |||
129 | /* | ||
130 | * This array hold the rest of parameters of int handlers: type | ||
131 | * (slow,fast,prio) and the name of the handler. These values are only | ||
132 | * accessed from C | ||
133 | */ | ||
134 | static struct irqparam irq_param[NUM_INT_SOURCES]; | ||
135 | |||
136 | /* | ||
137 | * Bitmap for free interrupt vector numbers | ||
138 | * (new vectors starting from 0x70 can be allocated by | ||
139 | * atari_register_vme_int()) | ||
140 | */ | ||
141 | static int free_vme_vec_bitmap; | ||
142 | |||
143 | /* check for valid int number (complex, sigh...) */ | ||
144 | #define IS_VALID_INTNO(n) \ | ||
145 | ((n) > 0 && \ | ||
146 | /* autovec and ST-MFP ok anyway */ \ | ||
147 | (((n) < TTMFP_SOURCE_BASE) || \ | ||
148 | /* TT-MFP ok if present */ \ | ||
149 | ((n) >= TTMFP_SOURCE_BASE && (n) < SCC_SOURCE_BASE && \ | ||
150 | ATARIHW_PRESENT(TT_MFP)) || \ | ||
151 | /* SCC ok if present and number even */ \ | ||
152 | ((n) >= SCC_SOURCE_BASE && (n) < VME_SOURCE_BASE && \ | ||
153 | !((n) & 1) && ATARIHW_PRESENT(SCC)) || \ | ||
154 | /* greater numbers ok if they are registered VME vectors */ \ | ||
155 | ((n) >= VME_SOURCE_BASE && (n) < VME_SOURCE_BASE + VME_MAX_SOURCES && \ | ||
156 | free_vme_vec_bitmap & (1 << ((n) - VME_SOURCE_BASE))))) | ||
157 | |||
158 | |||
159 | /* | ||
160 | * Here start the assembler entry points for interrupts | ||
161 | */ | ||
162 | |||
163 | #define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void) | ||
164 | |||
165 | #define BUILD_SLOW_IRQ(n) \ | ||
166 | asmlinkage void IRQ_NAME(n); \ | ||
167 | /* Dummy function to allow asm with operands. */ \ | ||
168 | void atari_slow_irq_##n##_dummy (void) { \ | ||
169 | __asm__ (__ALIGN_STR "\n" \ | ||
170 | "atari_slow_irq_" #n "_handler:\t" \ | ||
171 | " addl %6,%5\n" /* preempt_count() += HARDIRQ_OFFSET */ \ | ||
172 | SAVE_ALL_INT "\n" \ | ||
173 | GET_CURRENT(%%d0) "\n" \ | ||
174 | " andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \ | ||
175 | /* get old IPL from stack frame */ \ | ||
176 | " bfextu %%sp@(%c2){#5,#3},%%d0\n" \ | ||
177 | " movew %%sr,%%d1\n" \ | ||
178 | " bfins %%d0,%%d1{#21,#3}\n" \ | ||
179 | " movew %%d1,%%sr\n" /* set IPL = previous value */ \ | ||
180 | " addql #1,%a0\n" \ | ||
181 | " lea %a1,%%a0\n" \ | ||
182 | " pea %%sp@\n" /* push addr of frame */ \ | ||
183 | " movel %%a0@(4),%%sp@-\n" /* push handler data */ \ | ||
184 | " pea (%c3+8)\n" /* push int number */ \ | ||
185 | " movel %%a0@,%%a0\n" \ | ||
186 | " jbsr %%a0@\n" /* call the handler */ \ | ||
187 | " addql #8,%%sp\n" \ | ||
188 | " addql #4,%%sp\n" \ | ||
189 | " orw #0x0600,%%sr\n" \ | ||
190 | " andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \ | ||
191 | " orb #(1<<(%c3&7)),%a4:w\n" /* now unmask the int again */ \ | ||
192 | " jbra ret_from_interrupt\n" \ | ||
193 | : : "i" (&kstat_cpu(0).irqs[n+8]), "i" (&irq_handler[n+8]), \ | ||
194 | "n" (PT_OFF_SR), "n" (n), \ | ||
195 | "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \ | ||
196 | : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)), \ | ||
197 | "m" (preempt_count()), "di" (HARDIRQ_OFFSET) \ | ||
198 | ); \ | ||
199 | for (;;); /* fake noreturn */ \ | ||
200 | } | ||
201 | |||
202 | BUILD_SLOW_IRQ(0); | ||
203 | BUILD_SLOW_IRQ(1); | ||
204 | BUILD_SLOW_IRQ(2); | ||
205 | BUILD_SLOW_IRQ(3); | ||
206 | BUILD_SLOW_IRQ(4); | ||
207 | BUILD_SLOW_IRQ(5); | ||
208 | BUILD_SLOW_IRQ(6); | ||
209 | BUILD_SLOW_IRQ(7); | ||
210 | BUILD_SLOW_IRQ(8); | ||
211 | BUILD_SLOW_IRQ(9); | ||
212 | BUILD_SLOW_IRQ(10); | ||
213 | BUILD_SLOW_IRQ(11); | ||
214 | BUILD_SLOW_IRQ(12); | ||
215 | BUILD_SLOW_IRQ(13); | ||
216 | BUILD_SLOW_IRQ(14); | ||
217 | BUILD_SLOW_IRQ(15); | ||
218 | BUILD_SLOW_IRQ(16); | ||
219 | BUILD_SLOW_IRQ(17); | ||
220 | BUILD_SLOW_IRQ(18); | ||
221 | BUILD_SLOW_IRQ(19); | ||
222 | BUILD_SLOW_IRQ(20); | ||
223 | BUILD_SLOW_IRQ(21); | ||
224 | BUILD_SLOW_IRQ(22); | ||
225 | BUILD_SLOW_IRQ(23); | ||
226 | BUILD_SLOW_IRQ(24); | ||
227 | BUILD_SLOW_IRQ(25); | ||
228 | BUILD_SLOW_IRQ(26); | ||
229 | BUILD_SLOW_IRQ(27); | ||
230 | BUILD_SLOW_IRQ(28); | ||
231 | BUILD_SLOW_IRQ(29); | ||
232 | BUILD_SLOW_IRQ(30); | ||
233 | BUILD_SLOW_IRQ(31); | ||
234 | |||
235 | asm_irq_handler slow_handlers[32] = { | ||
236 | [0] = atari_slow_irq_0_handler, | ||
237 | [1] = atari_slow_irq_1_handler, | ||
238 | [2] = atari_slow_irq_2_handler, | ||
239 | [3] = atari_slow_irq_3_handler, | ||
240 | [4] = atari_slow_irq_4_handler, | ||
241 | [5] = atari_slow_irq_5_handler, | ||
242 | [6] = atari_slow_irq_6_handler, | ||
243 | [7] = atari_slow_irq_7_handler, | ||
244 | [8] = atari_slow_irq_8_handler, | ||
245 | [9] = atari_slow_irq_9_handler, | ||
246 | [10] = atari_slow_irq_10_handler, | ||
247 | [11] = atari_slow_irq_11_handler, | ||
248 | [12] = atari_slow_irq_12_handler, | ||
249 | [13] = atari_slow_irq_13_handler, | ||
250 | [14] = atari_slow_irq_14_handler, | ||
251 | [15] = atari_slow_irq_15_handler, | ||
252 | [16] = atari_slow_irq_16_handler, | ||
253 | [17] = atari_slow_irq_17_handler, | ||
254 | [18] = atari_slow_irq_18_handler, | ||
255 | [19] = atari_slow_irq_19_handler, | ||
256 | [20] = atari_slow_irq_20_handler, | ||
257 | [21] = atari_slow_irq_21_handler, | ||
258 | [22] = atari_slow_irq_22_handler, | ||
259 | [23] = atari_slow_irq_23_handler, | ||
260 | [24] = atari_slow_irq_24_handler, | ||
261 | [25] = atari_slow_irq_25_handler, | ||
262 | [26] = atari_slow_irq_26_handler, | ||
263 | [27] = atari_slow_irq_27_handler, | ||
264 | [28] = atari_slow_irq_28_handler, | ||
265 | [29] = atari_slow_irq_29_handler, | ||
266 | [30] = atari_slow_irq_30_handler, | ||
267 | [31] = atari_slow_irq_31_handler | ||
268 | }; | ||
269 | |||
270 | asmlinkage void atari_fast_irq_handler( void ); | ||
271 | asmlinkage void atari_prio_irq_handler( void ); | ||
272 | |||
273 | /* Dummy function to allow asm with operands. */ | ||
274 | void atari_fast_prio_irq_dummy (void) { | ||
275 | __asm__ (__ALIGN_STR "\n" | ||
276 | "atari_fast_irq_handler:\n\t" | ||
277 | "orw #0x700,%%sr\n" /* disable all interrupts */ | ||
278 | "atari_prio_irq_handler:\n\t" | ||
279 | "addl %3,%2\n\t" /* preempt_count() += HARDIRQ_OFFSET */ | ||
280 | SAVE_ALL_INT "\n\t" | ||
281 | GET_CURRENT(%%d0) "\n\t" | ||
282 | /* get vector number from stack frame and convert to source */ | ||
283 | "bfextu %%sp@(%c1){#4,#10},%%d0\n\t" | ||
284 | "subw #(0x40-8),%%d0\n\t" | ||
285 | "jpl 1f\n\t" | ||
286 | "addw #(0x40-8-0x18),%%d0\n" | ||
287 | "1:\tlea %a0,%%a0\n\t" | ||
288 | "addql #1,%%a0@(%%d0:l:4)\n\t" | ||
289 | "lea irq_handler,%%a0\n\t" | ||
290 | "lea %%a0@(%%d0:l:8),%%a0\n\t" | ||
291 | "pea %%sp@\n\t" /* push frame address */ | ||
292 | "movel %%a0@(4),%%sp@-\n\t" /* push handler data */ | ||
293 | "movel %%d0,%%sp@-\n\t" /* push int number */ | ||
294 | "movel %%a0@,%%a0\n\t" | ||
295 | "jsr %%a0@\n\t" /* and call the handler */ | ||
296 | "addql #8,%%sp\n\t" | ||
297 | "addql #4,%%sp\n\t" | ||
298 | "jbra ret_from_interrupt" | ||
299 | : : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC), | ||
300 | "m" (preempt_count()), "di" (HARDIRQ_OFFSET) | ||
301 | ); | ||
302 | for (;;); | ||
303 | } | ||
304 | |||
305 | /* GK: | ||
306 | * HBL IRQ handler for Falcon. Nobody needs it :-) | ||
307 | * ++andreas: raise ipl to disable further HBLANK interrupts. | ||
308 | */ | ||
309 | asmlinkage void falcon_hblhandler(void); | ||
310 | asm(".text\n" | ||
311 | __ALIGN_STR "\n\t" | ||
312 | "falcon_hblhandler:\n\t" | ||
313 | "orw #0x200,%sp@\n\t" /* set saved ipl to 2 */ | ||
314 | "rte"); | ||
315 | |||
316 | /* Defined in entry.S; only increments 'num_spurious' */ | ||
317 | asmlinkage void bad_interrupt(void); | ||
318 | |||
319 | extern void atari_microwire_cmd( int cmd ); | ||
320 | |||
321 | extern int atari_SCC_reset_done; | ||
322 | |||
323 | /* | ||
324 | * void atari_init_IRQ (void) | ||
325 | * | ||
326 | * Parameters: None | ||
327 | * | ||
328 | * Returns: Nothing | ||
329 | * | ||
330 | * This function should be called during kernel startup to initialize | ||
331 | * the atari IRQ handling routines. | ||
332 | */ | ||
333 | |||
334 | void __init atari_init_IRQ(void) | ||
335 | { | ||
336 | int i; | ||
337 | |||
338 | /* initialize the vector table */ | ||
339 | for (i = 0; i < NUM_INT_SOURCES; ++i) { | ||
340 | vectors[IRQ_SOURCE_TO_VECTOR(i)] = bad_interrupt; | ||
341 | } | ||
342 | |||
343 | /* Initialize the MFP(s) */ | ||
344 | |||
345 | #ifdef ATARI_USE_SOFTWARE_EOI | ||
346 | mfp.vec_adr = 0x48; /* Software EOI-Mode */ | ||
347 | #else | ||
348 | mfp.vec_adr = 0x40; /* Automatic EOI-Mode */ | ||
349 | #endif | ||
350 | mfp.int_en_a = 0x00; /* turn off MFP-Ints */ | ||
351 | mfp.int_en_b = 0x00; | ||
352 | mfp.int_mk_a = 0xff; /* no Masking */ | ||
353 | mfp.int_mk_b = 0xff; | ||
354 | |||
355 | if (ATARIHW_PRESENT(TT_MFP)) { | ||
356 | #ifdef ATARI_USE_SOFTWARE_EOI | ||
357 | tt_mfp.vec_adr = 0x58; /* Software EOI-Mode */ | ||
358 | #else | ||
359 | tt_mfp.vec_adr = 0x50; /* Automatic EOI-Mode */ | ||
360 | #endif | ||
361 | tt_mfp.int_en_a = 0x00; /* turn off MFP-Ints */ | ||
362 | tt_mfp.int_en_b = 0x00; | ||
363 | tt_mfp.int_mk_a = 0xff; /* no Masking */ | ||
364 | tt_mfp.int_mk_b = 0xff; | ||
365 | } | ||
366 | |||
367 | if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) { | ||
368 | scc.cha_a_ctrl = 9; | ||
369 | MFPDELAY(); | ||
370 | scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ | ||
371 | } | ||
372 | |||
373 | if (ATARIHW_PRESENT(SCU)) { | ||
374 | /* init the SCU if present */ | ||
375 | tt_scu.sys_mask = 0x10; /* enable VBL (for the cursor) and | ||
376 | * disable HSYNC interrupts (who | ||
377 | * needs them?) MFP and SCC are | ||
378 | * enabled in VME mask | ||
379 | */ | ||
380 | tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ | ||
381 | } | ||
382 | else { | ||
383 | /* If no SCU and no Hades, the HSYNC interrupt needs to be | ||
384 | * disabled this way. (Else _inthandler in kernel/sys_call.S | ||
385 | * gets overruns) | ||
386 | */ | ||
387 | |||
388 | if (!MACH_IS_HADES) | ||
389 | vectors[VEC_INT2] = falcon_hblhandler; | ||
390 | } | ||
391 | |||
392 | if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { | ||
393 | /* Initialize the LM1992 Sound Controller to enable | ||
394 | the PSG sound. This is misplaced here, it should | ||
395 | be in an atasound_init(), that doesn't exist yet. */ | ||
396 | atari_microwire_cmd(MW_LM1992_PSG_HIGH); | ||
397 | } | ||
398 | |||
399 | stdma_init(); | ||
400 | |||
401 | /* Initialize the PSG: all sounds off, both ports output */ | ||
402 | sound_ym.rd_data_reg_sel = 7; | ||
403 | sound_ym.wd_data = 0xff; | ||
404 | } | ||
405 | |||
406 | |||
407 | static irqreturn_t atari_call_irq_list( int irq, void *dev_id, struct pt_regs *fp ) | ||
408 | { | ||
409 | irq_node_t *node; | ||
410 | |||
411 | for (node = (irq_node_t *)dev_id; node; node = node->next) | ||
412 | node->handler(irq, node->dev_id, fp); | ||
413 | return IRQ_HANDLED; | ||
414 | } | ||
415 | |||
416 | |||
417 | /* | ||
418 | * atari_request_irq : add an interrupt service routine for a particular | ||
419 | * machine specific interrupt source. | ||
420 | * If the addition was successful, it returns 0. | ||
421 | */ | ||
422 | |||
423 | int atari_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
424 | unsigned long flags, const char *devname, void *dev_id) | ||
425 | { | ||
426 | int vector; | ||
427 | unsigned long oflags = flags; | ||
428 | |||
429 | /* | ||
430 | * The following is a hack to make some PCI card drivers work, | ||
431 | * which set the SA_SHIRQ flag. | ||
432 | */ | ||
433 | |||
434 | flags &= ~SA_SHIRQ; | ||
435 | |||
436 | if (flags == SA_INTERRUPT) { | ||
437 | printk ("%s: SA_INTERRUPT changed to IRQ_TYPE_SLOW for %s\n", | ||
438 | __FUNCTION__, devname); | ||
439 | flags = IRQ_TYPE_SLOW; | ||
440 | } | ||
441 | if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) { | ||
442 | printk ("%s: Bad irq type 0x%lx <0x%lx> requested from %s\n", | ||
443 | __FUNCTION__, flags, oflags, devname); | ||
444 | return -EINVAL; | ||
445 | } | ||
446 | if (!IS_VALID_INTNO(irq)) { | ||
447 | printk ("%s: Unknown irq %d requested from %s\n", | ||
448 | __FUNCTION__, irq, devname); | ||
449 | return -ENXIO; | ||
450 | } | ||
451 | vector = IRQ_SOURCE_TO_VECTOR(irq); | ||
452 | |||
453 | /* | ||
454 | * Check type/source combination: slow ints are (currently) | ||
455 | * only possible for MFP-interrupts. | ||
456 | */ | ||
457 | if (flags == IRQ_TYPE_SLOW && | ||
458 | (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE)) { | ||
459 | printk ("%s: Slow irq requested for non-MFP source %d from %s\n", | ||
460 | __FUNCTION__, irq, devname); | ||
461 | return -EINVAL; | ||
462 | } | ||
463 | |||
464 | if (vectors[vector] == bad_interrupt) { | ||
465 | /* int has no handler yet */ | ||
466 | irq_handler[irq].handler = handler; | ||
467 | irq_handler[irq].dev_id = dev_id; | ||
468 | irq_param[irq].flags = flags; | ||
469 | irq_param[irq].devname = devname; | ||
470 | vectors[vector] = | ||
471 | (flags == IRQ_TYPE_SLOW) ? slow_handlers[irq-STMFP_SOURCE_BASE] : | ||
472 | (flags == IRQ_TYPE_FAST) ? atari_fast_irq_handler : | ||
473 | atari_prio_irq_handler; | ||
474 | /* If MFP int, also enable and umask it */ | ||
475 | atari_turnon_irq(irq); | ||
476 | atari_enable_irq(irq); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | else if (irq_param[irq].flags == flags) { | ||
481 | /* old handler is of same type -> handlers can be chained */ | ||
482 | irq_node_t *node; | ||
483 | unsigned long flags; | ||
484 | |||
485 | local_irq_save(flags); | ||
486 | |||
487 | if (irq_handler[irq].handler != atari_call_irq_list) { | ||
488 | /* Only one handler yet, make a node for this first one */ | ||
489 | if (!(node = new_irq_node())) | ||
490 | return -ENOMEM; | ||
491 | node->handler = irq_handler[irq].handler; | ||
492 | node->dev_id = irq_handler[irq].dev_id; | ||
493 | node->devname = irq_param[irq].devname; | ||
494 | node->next = NULL; | ||
495 | |||
496 | irq_handler[irq].handler = atari_call_irq_list; | ||
497 | irq_handler[irq].dev_id = node; | ||
498 | irq_param[irq].devname = "chained"; | ||
499 | } | ||
500 | |||
501 | if (!(node = new_irq_node())) | ||
502 | return -ENOMEM; | ||
503 | node->handler = handler; | ||
504 | node->dev_id = dev_id; | ||
505 | node->devname = devname; | ||
506 | /* new handlers are put in front of the queue */ | ||
507 | node->next = irq_handler[irq].dev_id; | ||
508 | irq_handler[irq].dev_id = node; | ||
509 | |||
510 | local_irq_restore(flags); | ||
511 | return 0; | ||
512 | } else { | ||
513 | printk ("%s: Irq %d allocated by other type int (call from %s)\n", | ||
514 | __FUNCTION__, irq, devname); | ||
515 | return -EBUSY; | ||
516 | } | ||
517 | } | ||
518 | |||
519 | void atari_free_irq(unsigned int irq, void *dev_id) | ||
520 | { | ||
521 | unsigned long flags; | ||
522 | int vector; | ||
523 | irq_node_t **list, *node; | ||
524 | |||
525 | if (!IS_VALID_INTNO(irq)) { | ||
526 | printk("%s: Unknown irq %d\n", __FUNCTION__, irq); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | vector = IRQ_SOURCE_TO_VECTOR(irq); | ||
531 | if (vectors[vector] == bad_interrupt) | ||
532 | goto not_found; | ||
533 | |||
534 | local_irq_save(flags); | ||
535 | |||
536 | if (irq_handler[irq].handler != atari_call_irq_list) { | ||
537 | /* It's the only handler for the interrupt */ | ||
538 | if (irq_handler[irq].dev_id != dev_id) { | ||
539 | local_irq_restore(flags); | ||
540 | goto not_found; | ||
541 | } | ||
542 | irq_handler[irq].handler = NULL; | ||
543 | irq_handler[irq].dev_id = NULL; | ||
544 | irq_param[irq].devname = NULL; | ||
545 | vectors[vector] = bad_interrupt; | ||
546 | /* If MFP int, also disable it */ | ||
547 | atari_disable_irq(irq); | ||
548 | atari_turnoff_irq(irq); | ||
549 | |||
550 | local_irq_restore(flags); | ||
551 | return; | ||
552 | } | ||
553 | |||
554 | /* The interrupt is chained, find the irq on the list */ | ||
555 | for(list = (irq_node_t **)&irq_handler[irq].dev_id; *list; list = &(*list)->next) { | ||
556 | if ((*list)->dev_id == dev_id) break; | ||
557 | } | ||
558 | if (!*list) { | ||
559 | local_irq_restore(flags); | ||
560 | goto not_found; | ||
561 | } | ||
562 | |||
563 | (*list)->handler = NULL; /* Mark it as free for reallocation */ | ||
564 | *list = (*list)->next; | ||
565 | |||
566 | /* If there's now only one handler, unchain the interrupt, i.e. plug in | ||
567 | * the handler directly again and omit atari_call_irq_list */ | ||
568 | node = (irq_node_t *)irq_handler[irq].dev_id; | ||
569 | if (node && !node->next) { | ||
570 | irq_handler[irq].handler = node->handler; | ||
571 | irq_handler[irq].dev_id = node->dev_id; | ||
572 | irq_param[irq].devname = node->devname; | ||
573 | node->handler = NULL; /* Mark it as free for reallocation */ | ||
574 | } | ||
575 | |||
576 | local_irq_restore(flags); | ||
577 | return; | ||
578 | |||
579 | not_found: | ||
580 | printk("%s: tried to remove invalid irq\n", __FUNCTION__); | ||
581 | return; | ||
582 | } | ||
583 | |||
584 | |||
585 | /* | ||
586 | * atari_register_vme_int() returns the number of a free interrupt vector for | ||
587 | * hardware with a programmable int vector (probably a VME board). | ||
588 | */ | ||
589 | |||
590 | unsigned long atari_register_vme_int(void) | ||
591 | { | ||
592 | int i; | ||
593 | |||
594 | for(i = 0; i < 32; i++) | ||
595 | if((free_vme_vec_bitmap & (1 << i)) == 0) | ||
596 | break; | ||
597 | |||
598 | if(i == 16) | ||
599 | return 0; | ||
600 | |||
601 | free_vme_vec_bitmap |= 1 << i; | ||
602 | return (VME_SOURCE_BASE + i); | ||
603 | } | ||
604 | |||
605 | |||
606 | void atari_unregister_vme_int(unsigned long irq) | ||
607 | { | ||
608 | if(irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) { | ||
609 | irq -= VME_SOURCE_BASE; | ||
610 | free_vme_vec_bitmap &= ~(1 << irq); | ||
611 | } | ||
612 | } | ||
613 | |||
614 | |||
615 | int show_atari_interrupts(struct seq_file *p, void *v) | ||
616 | { | ||
617 | int i; | ||
618 | |||
619 | for (i = 0; i < NUM_INT_SOURCES; ++i) { | ||
620 | if (vectors[IRQ_SOURCE_TO_VECTOR(i)] == bad_interrupt) | ||
621 | continue; | ||
622 | if (i < STMFP_SOURCE_BASE) | ||
623 | seq_printf(p, "auto %2d: %10u ", | ||
624 | i, kstat_cpu(0).irqs[i]); | ||
625 | else | ||
626 | seq_printf(p, "vec $%02x: %10u ", | ||
627 | IRQ_SOURCE_TO_VECTOR(i), | ||
628 | kstat_cpu(0).irqs[i]); | ||
629 | |||
630 | if (irq_handler[i].handler != atari_call_irq_list) { | ||
631 | seq_printf(p, "%s\n", irq_param[i].devname); | ||
632 | } | ||
633 | else { | ||
634 | irq_node_t *n; | ||
635 | for( n = (irq_node_t *)irq_handler[i].dev_id; n; n = n->next ) { | ||
636 | seq_printf(p, "%s\n", n->devname); | ||
637 | if (n->next) | ||
638 | seq_puts(p, " " ); | ||
639 | } | ||
640 | } | ||
641 | } | ||
642 | if (num_spurious) | ||
643 | seq_printf(p, "spurio.: %10u\n", num_spurious); | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | |||
diff --git a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c new file mode 100644 index 000000000000..a04757151538 --- /dev/null +++ b/arch/m68k/atari/atari_ksyms.c | |||
@@ -0,0 +1,35 @@ | |||
1 | #include <linux/module.h> | ||
2 | |||
3 | #include <asm/ptrace.h> | ||
4 | #include <asm/traps.h> | ||
5 | #include <asm/atarihw.h> | ||
6 | #include <asm/atariints.h> | ||
7 | #include <asm/atarikb.h> | ||
8 | #include <asm/atari_joystick.h> | ||
9 | #include <asm/atari_stdma.h> | ||
10 | #include <asm/atari_stram.h> | ||
11 | |||
12 | extern void atari_microwire_cmd( int cmd ); | ||
13 | extern int atari_MFP_init_done; | ||
14 | extern int atari_SCC_init_done; | ||
15 | extern int atari_SCC_reset_done; | ||
16 | |||
17 | EXPORT_SYMBOL(atari_mch_cookie); | ||
18 | EXPORT_SYMBOL(atari_mch_type); | ||
19 | EXPORT_SYMBOL(atari_hw_present); | ||
20 | EXPORT_SYMBOL(atari_switches); | ||
21 | EXPORT_SYMBOL(atari_dont_touch_floppy_select); | ||
22 | EXPORT_SYMBOL(atari_register_vme_int); | ||
23 | EXPORT_SYMBOL(atari_unregister_vme_int); | ||
24 | EXPORT_SYMBOL(stdma_lock); | ||
25 | EXPORT_SYMBOL(stdma_release); | ||
26 | EXPORT_SYMBOL(stdma_others_waiting); | ||
27 | EXPORT_SYMBOL(stdma_islocked); | ||
28 | EXPORT_SYMBOL(atari_stram_alloc); | ||
29 | EXPORT_SYMBOL(atari_stram_free); | ||
30 | |||
31 | EXPORT_SYMBOL(atari_MFP_init_done); | ||
32 | EXPORT_SYMBOL(atari_SCC_init_done); | ||
33 | EXPORT_SYMBOL(atari_SCC_reset_done); | ||
34 | |||
35 | EXPORT_SYMBOL(atari_microwire_cmd); | ||
diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c new file mode 100644 index 000000000000..ee04250eb56b --- /dev/null +++ b/arch/m68k/atari/atasound.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/atari/atasound.c | ||
3 | * | ||
4 | * ++Geert: Moved almost all stuff to linux/drivers/sound/ | ||
5 | * | ||
6 | * The author of atari_nosound, atari_mksound and atari_microwire_cmd is | ||
7 | * unknown. (++roman: That's me... :-) | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file COPYING in the main directory of this archive | ||
11 | * for more details. | ||
12 | * | ||
13 | * 1998-05-31 ++andreas: atari_mksound rewritten to always use the envelope, | ||
14 | * no timer, atari_nosound removed. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/sched.h> | ||
20 | #include <linux/timer.h> | ||
21 | #include <linux/major.h> | ||
22 | #include <linux/fcntl.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/mm.h> | ||
25 | |||
26 | #include <asm/atarihw.h> | ||
27 | #include <asm/system.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/pgtable.h> | ||
30 | #include <asm/atariints.h> | ||
31 | |||
32 | |||
33 | /* | ||
34 | * stuff from the old atasound.c | ||
35 | */ | ||
36 | |||
37 | void atari_microwire_cmd (int cmd) | ||
38 | { | ||
39 | tt_microwire.mask = 0x7ff; | ||
40 | tt_microwire.data = MW_LM1992_ADDR | cmd; | ||
41 | |||
42 | /* Busy wait for data being completely sent :-( */ | ||
43 | while( tt_microwire.mask != 0x7ff) | ||
44 | ; | ||
45 | } | ||
46 | |||
47 | |||
48 | /* PSG base frequency */ | ||
49 | #define PSG_FREQ 125000 | ||
50 | /* PSG envelope base frequency times 10 */ | ||
51 | #define PSG_ENV_FREQ_10 78125 | ||
52 | |||
53 | void atari_mksound (unsigned int hz, unsigned int ticks) | ||
54 | { | ||
55 | /* Generates sound of some frequency for some number of clock | ||
56 | ticks. */ | ||
57 | unsigned long flags; | ||
58 | unsigned char tmp; | ||
59 | int period; | ||
60 | |||
61 | local_irq_save(flags); | ||
62 | |||
63 | |||
64 | /* Disable generator A in mixer control. */ | ||
65 | sound_ym.rd_data_reg_sel = 7; | ||
66 | tmp = sound_ym.rd_data_reg_sel; | ||
67 | tmp |= 011; | ||
68 | sound_ym.wd_data = tmp; | ||
69 | |||
70 | if (hz) { | ||
71 | /* Convert from frequency value to PSG period value (base | ||
72 | frequency 125 kHz). */ | ||
73 | |||
74 | period = PSG_FREQ / hz; | ||
75 | |||
76 | if (period > 0xfff) period = 0xfff; | ||
77 | |||
78 | /* Set generator A frequency to hz. */ | ||
79 | sound_ym.rd_data_reg_sel = 0; | ||
80 | sound_ym.wd_data = period & 0xff; | ||
81 | sound_ym.rd_data_reg_sel = 1; | ||
82 | sound_ym.wd_data = (period >> 8) & 0xf; | ||
83 | if (ticks) { | ||
84 | /* Set length of envelope (max 8 sec). */ | ||
85 | int length = (ticks * PSG_ENV_FREQ_10) / HZ / 10; | ||
86 | |||
87 | if (length > 0xffff) length = 0xffff; | ||
88 | sound_ym.rd_data_reg_sel = 11; | ||
89 | sound_ym.wd_data = length & 0xff; | ||
90 | sound_ym.rd_data_reg_sel = 12; | ||
91 | sound_ym.wd_data = length >> 8; | ||
92 | /* Envelope form: max -> min single. */ | ||
93 | sound_ym.rd_data_reg_sel = 13; | ||
94 | sound_ym.wd_data = 0; | ||
95 | /* Use envelope for generator A. */ | ||
96 | sound_ym.rd_data_reg_sel = 8; | ||
97 | sound_ym.wd_data = 0x10; | ||
98 | } else { | ||
99 | /* Set generator A level to maximum, no envelope. */ | ||
100 | sound_ym.rd_data_reg_sel = 8; | ||
101 | sound_ym.wd_data = 15; | ||
102 | } | ||
103 | /* Turn on generator A in mixer control. */ | ||
104 | sound_ym.rd_data_reg_sel = 7; | ||
105 | tmp &= ~1; | ||
106 | sound_ym.wd_data = tmp; | ||
107 | } | ||
108 | local_irq_restore(flags); | ||
109 | } | ||
diff --git a/arch/m68k/atari/atasound.h b/arch/m68k/atari/atasound.h new file mode 100644 index 000000000000..1362762b8c0f --- /dev/null +++ b/arch/m68k/atari/atasound.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Minor numbers for the sound driver. | ||
3 | * | ||
4 | * Unfortunately Creative called the codec chip of SB as a DSP. For this | ||
5 | * reason the /dev/dsp is reserved for digitized audio use. There is a | ||
6 | * device for true DSP processors but it will be called something else. | ||
7 | * In v3.0 it's /dev/sndproc but this could be a temporary solution. | ||
8 | */ | ||
9 | |||
10 | #define SND_NDEVS 256 /* Number of supported devices */ | ||
11 | #define SND_DEV_CTL 0 /* Control port /dev/mixer */ | ||
12 | #define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM | ||
13 | synthesizer and MIDI output) */ | ||
14 | #define SND_DEV_MIDIN 2 /* Raw midi access */ | ||
15 | #define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ | ||
16 | #define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ | ||
17 | #define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ | ||
18 | #define SND_DEV_STATUS 6 /* /dev/sndstat */ | ||
19 | /* #7 not in use now. Was in 2.4. Free for use after v3.0. */ | ||
20 | #define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ | ||
21 | #define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ | ||
22 | #define SND_DEV_PSS SND_DEV_SNDPROC | ||
23 | |||
24 | #define DSP_DEFAULT_SPEED 8000 | ||
25 | |||
26 | #define ON 1 | ||
27 | #define OFF 0 | ||
28 | |||
29 | #define MAX_AUDIO_DEV 5 | ||
30 | #define MAX_MIXER_DEV 2 | ||
31 | #define MAX_SYNTH_DEV 3 | ||
32 | #define MAX_MIDI_DEV 6 | ||
33 | #define MAX_TIMER_DEV 3 | ||
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c new file mode 100644 index 000000000000..9261d2deeaf5 --- /dev/null +++ b/arch/m68k/atari/config.c | |||
@@ -0,0 +1,726 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/atari/config.c | ||
3 | * | ||
4 | * Copyright (C) 1994 Bjoern Brauel | ||
5 | * | ||
6 | * 5/2/94 Roman Hodek: | ||
7 | * Added setting of time_adj to get a better clock. | ||
8 | * | ||
9 | * 5/14/94 Roman Hodek: | ||
10 | * gettod() for TT | ||
11 | * | ||
12 | * 5/15/94 Roman Hodek: | ||
13 | * hard_reset_now() for Atari (and others?) | ||
14 | * | ||
15 | * 94/12/30 Andreas Schwab: | ||
16 | * atari_sched_init fixed to get precise clock. | ||
17 | * | ||
18 | * This file is subject to the terms and conditions of the GNU General Public | ||
19 | * License. See the file COPYING in the main directory of this archive | ||
20 | * for more details. | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * Miscellaneous atari stuff | ||
25 | */ | ||
26 | |||
27 | #include <linux/config.h> | ||
28 | #include <linux/types.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/console.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/ioport.h> | ||
34 | #include <linux/vt_kern.h> | ||
35 | |||
36 | #include <asm/bootinfo.h> | ||
37 | #include <asm/setup.h> | ||
38 | #include <asm/atarihw.h> | ||
39 | #include <asm/atariints.h> | ||
40 | #include <asm/atari_stram.h> | ||
41 | #include <asm/system.h> | ||
42 | #include <asm/machdep.h> | ||
43 | #include <asm/hwtest.h> | ||
44 | #include <asm/io.h> | ||
45 | |||
46 | u_long atari_mch_cookie; | ||
47 | u_long atari_mch_type; | ||
48 | struct atari_hw_present atari_hw_present; | ||
49 | u_long atari_switches; | ||
50 | int atari_dont_touch_floppy_select; | ||
51 | int atari_rtc_year_offset; | ||
52 | |||
53 | /* local function prototypes */ | ||
54 | static void atari_reset( void ); | ||
55 | #ifdef CONFIG_ATARI_FLOPPY | ||
56 | extern void atari_floppy_setup(char *, int *); | ||
57 | #endif | ||
58 | static void atari_get_model(char *model); | ||
59 | static int atari_get_hardware_list(char *buffer); | ||
60 | |||
61 | /* atari specific irq functions */ | ||
62 | extern void atari_init_IRQ (void); | ||
63 | extern int atari_request_irq (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
64 | unsigned long flags, const char *devname, void *dev_id); | ||
65 | extern void atari_free_irq (unsigned int irq, void *dev_id); | ||
66 | extern void atari_enable_irq (unsigned int); | ||
67 | extern void atari_disable_irq (unsigned int); | ||
68 | extern int show_atari_interrupts (struct seq_file *, void *); | ||
69 | extern void atari_mksound( unsigned int count, unsigned int ticks ); | ||
70 | #ifdef CONFIG_HEARTBEAT | ||
71 | static void atari_heartbeat( int on ); | ||
72 | #endif | ||
73 | |||
74 | /* atari specific timer functions (in time.c) */ | ||
75 | extern void atari_sched_init(irqreturn_t (*)(int, void *, struct pt_regs *)); | ||
76 | extern unsigned long atari_gettimeoffset (void); | ||
77 | extern int atari_mste_hwclk (int, struct rtc_time *); | ||
78 | extern int atari_tt_hwclk (int, struct rtc_time *); | ||
79 | extern int atari_mste_set_clock_mmss (unsigned long); | ||
80 | extern int atari_tt_set_clock_mmss (unsigned long); | ||
81 | |||
82 | /* atari specific debug functions (in debug.c) */ | ||
83 | extern void atari_debug_init(void); | ||
84 | |||
85 | |||
86 | /* I've moved hwreg_present() and hwreg_present_bywrite() out into | ||
87 | * mm/hwtest.c, to avoid having multiple copies of the same routine | ||
88 | * in the kernel [I wanted them in hp300 and they were already used | ||
89 | * in the nubus code. NB: I don't have an Atari so this might (just | ||
90 | * conceivably) break something. | ||
91 | * I've preserved the #if 0 version of hwreg_present_bywrite() here | ||
92 | * for posterity. | ||
93 | * -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998 | ||
94 | */ | ||
95 | |||
96 | #if 0 | ||
97 | static int __init | ||
98 | hwreg_present_bywrite(volatile void *regp, unsigned char val) | ||
99 | { | ||
100 | int ret; | ||
101 | long save_sp, save_vbr; | ||
102 | static long tmp_vectors[3] = { [2] = (long)&&after_test }; | ||
103 | |||
104 | __asm__ __volatile__ | ||
105 | ( "movec %/vbr,%2\n\t" /* save vbr value */ | ||
106 | "movec %4,%/vbr\n\t" /* set up temporary vectors */ | ||
107 | "movel %/sp,%1\n\t" /* save sp */ | ||
108 | "moveq #0,%0\n\t" /* assume not present */ | ||
109 | "moveb %5,%3@\n\t" /* write the hardware reg */ | ||
110 | "cmpb %3@,%5\n\t" /* compare it */ | ||
111 | "seq %0" /* comes here only if reg */ | ||
112 | /* is present */ | ||
113 | : "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr) | ||
114 | : "a" (regp), "r" (tmp_vectors), "d" (val) | ||
115 | ); | ||
116 | after_test: | ||
117 | __asm__ __volatile__ | ||
118 | ( "movel %0,%/sp\n\t" /* restore sp */ | ||
119 | "movec %1,%/vbr" /* restore vbr */ | ||
120 | : : "r" (save_sp), "r" (save_vbr) : "sp" | ||
121 | ); | ||
122 | |||
123 | return( ret ); | ||
124 | } | ||
125 | #endif | ||
126 | |||
127 | |||
128 | /* ++roman: This is a more elaborate test for an SCC chip, since the plain | ||
129 | * Medusa board generates DTACK at the SCC's standard addresses, but a SCC | ||
130 | * board in the Medusa is possible. Also, the addresses where the ST_ESCC | ||
131 | * resides generate DTACK without the chip, too. | ||
132 | * The method is to write values into the interrupt vector register, that | ||
133 | * should be readable without trouble (from channel A!). | ||
134 | */ | ||
135 | |||
136 | static int __init scc_test( volatile char *ctla ) | ||
137 | { | ||
138 | if (!hwreg_present( ctla )) | ||
139 | return( 0 ); | ||
140 | MFPDELAY(); | ||
141 | |||
142 | *ctla = 2; MFPDELAY(); | ||
143 | *ctla = 0x40; MFPDELAY(); | ||
144 | |||
145 | *ctla = 2; MFPDELAY(); | ||
146 | if (*ctla != 0x40) return( 0 ); | ||
147 | MFPDELAY(); | ||
148 | |||
149 | *ctla = 2; MFPDELAY(); | ||
150 | *ctla = 0x60; MFPDELAY(); | ||
151 | |||
152 | *ctla = 2; MFPDELAY(); | ||
153 | if (*ctla != 0x60) return( 0 ); | ||
154 | |||
155 | return( 1 ); | ||
156 | } | ||
157 | |||
158 | |||
159 | /* | ||
160 | * Parse an Atari-specific record in the bootinfo | ||
161 | */ | ||
162 | |||
163 | int __init atari_parse_bootinfo(const struct bi_record *record) | ||
164 | { | ||
165 | int unknown = 0; | ||
166 | const u_long *data = record->data; | ||
167 | |||
168 | switch (record->tag) { | ||
169 | case BI_ATARI_MCH_COOKIE: | ||
170 | atari_mch_cookie = *data; | ||
171 | break; | ||
172 | case BI_ATARI_MCH_TYPE: | ||
173 | atari_mch_type = *data; | ||
174 | break; | ||
175 | default: | ||
176 | unknown = 1; | ||
177 | } | ||
178 | return(unknown); | ||
179 | } | ||
180 | |||
181 | |||
182 | /* Parse the Atari-specific switches= option. */ | ||
183 | void __init atari_switches_setup( const char *str, unsigned len ) | ||
184 | { | ||
185 | char switches[len+1]; | ||
186 | char *p; | ||
187 | int ovsc_shift; | ||
188 | char *args = switches; | ||
189 | |||
190 | /* copy string to local array, strsep works destructively... */ | ||
191 | strlcpy( switches, str, sizeof(switches) ); | ||
192 | atari_switches = 0; | ||
193 | |||
194 | /* parse the options */ | ||
195 | while ((p = strsep(&args, ",")) != NULL) { | ||
196 | if (!*p) continue; | ||
197 | ovsc_shift = 0; | ||
198 | if (strncmp( p, "ov_", 3 ) == 0) { | ||
199 | p += 3; | ||
200 | ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; | ||
201 | } | ||
202 | |||
203 | if (strcmp( p, "ikbd" ) == 0) { | ||
204 | /* RTS line of IKBD ACIA */ | ||
205 | atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; | ||
206 | } | ||
207 | else if (strcmp( p, "midi" ) == 0) { | ||
208 | /* RTS line of MIDI ACIA */ | ||
209 | atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; | ||
210 | } | ||
211 | else if (strcmp( p, "snd6" ) == 0) { | ||
212 | atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; | ||
213 | } | ||
214 | else if (strcmp( p, "snd7" ) == 0) { | ||
215 | atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | |||
221 | /* | ||
222 | * Setup the Atari configuration info | ||
223 | */ | ||
224 | |||
225 | void __init config_atari(void) | ||
226 | { | ||
227 | unsigned short tos_version; | ||
228 | |||
229 | memset(&atari_hw_present, 0, sizeof(atari_hw_present)); | ||
230 | |||
231 | atari_debug_init(); | ||
232 | |||
233 | ioport_resource.end = 0xFFFFFFFF; /* Change size of I/O space from 64KB | ||
234 | to 4GB. */ | ||
235 | |||
236 | mach_sched_init = atari_sched_init; | ||
237 | mach_init_IRQ = atari_init_IRQ; | ||
238 | mach_request_irq = atari_request_irq; | ||
239 | mach_free_irq = atari_free_irq; | ||
240 | enable_irq = atari_enable_irq; | ||
241 | disable_irq = atari_disable_irq; | ||
242 | mach_get_model = atari_get_model; | ||
243 | mach_get_hardware_list = atari_get_hardware_list; | ||
244 | mach_get_irq_list = show_atari_interrupts; | ||
245 | mach_gettimeoffset = atari_gettimeoffset; | ||
246 | mach_reset = atari_reset; | ||
247 | #ifdef CONFIG_ATARI_FLOPPY | ||
248 | mach_floppy_setup = atari_floppy_setup; | ||
249 | #endif | ||
250 | #ifdef CONFIG_DUMMY_CONSOLE | ||
251 | conswitchp = &dummy_con; | ||
252 | #endif | ||
253 | mach_max_dma_address = 0xffffff; | ||
254 | #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) | ||
255 | mach_beep = atari_mksound; | ||
256 | #endif | ||
257 | #ifdef CONFIG_HEARTBEAT | ||
258 | mach_heartbeat = atari_heartbeat; | ||
259 | #endif | ||
260 | |||
261 | /* Set switches as requested by the user */ | ||
262 | if (atari_switches & ATARI_SWITCH_IKBD) | ||
263 | acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; | ||
264 | if (atari_switches & ATARI_SWITCH_MIDI) | ||
265 | acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; | ||
266 | if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { | ||
267 | sound_ym.rd_data_reg_sel = 14; | ||
268 | sound_ym.wd_data = sound_ym.rd_data_reg_sel | | ||
269 | ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | | ||
270 | ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); | ||
271 | } | ||
272 | |||
273 | /* ++bjoern: | ||
274 | * Determine hardware present | ||
275 | */ | ||
276 | |||
277 | printk( "Atari hardware found: " ); | ||
278 | if (MACH_IS_MEDUSA || MACH_IS_HADES) { | ||
279 | /* There's no Atari video hardware on the Medusa, but all the | ||
280 | * addresses below generate a DTACK so no bus error occurs! */ | ||
281 | } | ||
282 | else if (hwreg_present( f030_xreg )) { | ||
283 | ATARIHW_SET(VIDEL_SHIFTER); | ||
284 | printk( "VIDEL " ); | ||
285 | /* This is a temporary hack: If there is Falcon video | ||
286 | * hardware, we assume that the ST-DMA serves SCSI instead of | ||
287 | * ACSI. In the future, there should be a better method for | ||
288 | * this... | ||
289 | */ | ||
290 | ATARIHW_SET(ST_SCSI); | ||
291 | printk( "STDMA-SCSI " ); | ||
292 | } | ||
293 | else if (hwreg_present( tt_palette )) { | ||
294 | ATARIHW_SET(TT_SHIFTER); | ||
295 | printk( "TT_SHIFTER " ); | ||
296 | } | ||
297 | else if (hwreg_present( &shifter.bas_hi )) { | ||
298 | if (hwreg_present( &shifter.bas_lo ) && | ||
299 | (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { | ||
300 | ATARIHW_SET(EXTD_SHIFTER); | ||
301 | printk( "EXTD_SHIFTER " ); | ||
302 | } | ||
303 | else { | ||
304 | ATARIHW_SET(STND_SHIFTER); | ||
305 | printk( "STND_SHIFTER " ); | ||
306 | } | ||
307 | } | ||
308 | if (hwreg_present( &mfp.par_dt_reg )) { | ||
309 | ATARIHW_SET(ST_MFP); | ||
310 | printk( "ST_MFP " ); | ||
311 | } | ||
312 | if (hwreg_present( &tt_mfp.par_dt_reg )) { | ||
313 | ATARIHW_SET(TT_MFP); | ||
314 | printk( "TT_MFP " ); | ||
315 | } | ||
316 | if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) { | ||
317 | ATARIHW_SET(SCSI_DMA); | ||
318 | printk( "TT_SCSI_DMA " ); | ||
319 | } | ||
320 | if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) { | ||
321 | ATARIHW_SET(STND_DMA); | ||
322 | printk( "STND_DMA " ); | ||
323 | } | ||
324 | if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable | ||
325 | * on all Medusas, so the test below may fail */ | ||
326 | (hwreg_present( &st_dma.dma_vhi ) && | ||
327 | (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && | ||
328 | st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && | ||
329 | (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) && | ||
330 | st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) { | ||
331 | ATARIHW_SET(EXTD_DMA); | ||
332 | printk( "EXTD_DMA " ); | ||
333 | } | ||
334 | if (hwreg_present( &tt_scsi.scsi_data )) { | ||
335 | ATARIHW_SET(TT_SCSI); | ||
336 | printk( "TT_SCSI " ); | ||
337 | } | ||
338 | if (hwreg_present( &sound_ym.rd_data_reg_sel )) { | ||
339 | ATARIHW_SET(YM_2149); | ||
340 | printk( "YM2149 " ); | ||
341 | } | ||
342 | if (!MACH_IS_MEDUSA && !MACH_IS_HADES && | ||
343 | hwreg_present( &tt_dmasnd.ctrl )) { | ||
344 | ATARIHW_SET(PCM_8BIT); | ||
345 | printk( "PCM " ); | ||
346 | } | ||
347 | if (!MACH_IS_HADES && hwreg_present( &falcon_codec.unused5 )) { | ||
348 | ATARIHW_SET(CODEC); | ||
349 | printk( "CODEC " ); | ||
350 | } | ||
351 | if (hwreg_present( &dsp56k_host_interface.icr )) { | ||
352 | ATARIHW_SET(DSP56K); | ||
353 | printk( "DSP56K " ); | ||
354 | } | ||
355 | if (hwreg_present( &tt_scc_dma.dma_ctrl ) && | ||
356 | #if 0 | ||
357 | /* This test sucks! Who knows some better? */ | ||
358 | (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && | ||
359 | (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) | ||
360 | #else | ||
361 | !MACH_IS_MEDUSA && !MACH_IS_HADES | ||
362 | #endif | ||
363 | ) { | ||
364 | ATARIHW_SET(SCC_DMA); | ||
365 | printk( "SCC_DMA " ); | ||
366 | } | ||
367 | if (scc_test( &scc.cha_a_ctrl )) { | ||
368 | ATARIHW_SET(SCC); | ||
369 | printk( "SCC " ); | ||
370 | } | ||
371 | if (scc_test( &st_escc.cha_b_ctrl )) { | ||
372 | ATARIHW_SET( ST_ESCC ); | ||
373 | printk( "ST_ESCC " ); | ||
374 | } | ||
375 | if (MACH_IS_HADES) | ||
376 | { | ||
377 | ATARIHW_SET( VME ); | ||
378 | printk( "VME " ); | ||
379 | } | ||
380 | else if (hwreg_present( &tt_scu.sys_mask )) { | ||
381 | ATARIHW_SET(SCU); | ||
382 | /* Assume a VME bus if there's a SCU */ | ||
383 | ATARIHW_SET( VME ); | ||
384 | printk( "VME SCU " ); | ||
385 | } | ||
386 | if (hwreg_present( (void *)(0xffff9210) )) { | ||
387 | ATARIHW_SET(ANALOG_JOY); | ||
388 | printk( "ANALOG_JOY " ); | ||
389 | } | ||
390 | if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) { | ||
391 | ATARIHW_SET(BLITTER); | ||
392 | printk( "BLITTER " ); | ||
393 | } | ||
394 | if (hwreg_present((void *)0xfff00039)) { | ||
395 | ATARIHW_SET(IDE); | ||
396 | printk( "IDE " ); | ||
397 | } | ||
398 | #if 1 /* This maybe wrong */ | ||
399 | if (!MACH_IS_MEDUSA && !MACH_IS_HADES && | ||
400 | hwreg_present( &tt_microwire.data ) && | ||
401 | hwreg_present( &tt_microwire.mask ) && | ||
402 | (tt_microwire.mask = 0x7ff, | ||
403 | udelay(1), | ||
404 | tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, | ||
405 | udelay(1), | ||
406 | tt_microwire.data != 0)) { | ||
407 | ATARIHW_SET(MICROWIRE); | ||
408 | while (tt_microwire.mask != 0x7ff) ; | ||
409 | printk( "MICROWIRE " ); | ||
410 | } | ||
411 | #endif | ||
412 | if (hwreg_present( &tt_rtc.regsel )) { | ||
413 | ATARIHW_SET(TT_CLK); | ||
414 | printk( "TT_CLK " ); | ||
415 | mach_hwclk = atari_tt_hwclk; | ||
416 | mach_set_clock_mmss = atari_tt_set_clock_mmss; | ||
417 | } | ||
418 | if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) { | ||
419 | ATARIHW_SET(MSTE_CLK); | ||
420 | printk( "MSTE_CLK "); | ||
421 | mach_hwclk = atari_mste_hwclk; | ||
422 | mach_set_clock_mmss = atari_mste_set_clock_mmss; | ||
423 | } | ||
424 | if (!MACH_IS_MEDUSA && !MACH_IS_HADES && | ||
425 | hwreg_present( &dma_wd.fdc_speed ) && | ||
426 | hwreg_write( &dma_wd.fdc_speed, 0 )) { | ||
427 | ATARIHW_SET(FDCSPEED); | ||
428 | printk( "FDC_SPEED "); | ||
429 | } | ||
430 | if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { | ||
431 | ATARIHW_SET(ACSI); | ||
432 | printk( "ACSI " ); | ||
433 | } | ||
434 | printk("\n"); | ||
435 | |||
436 | if (CPU_IS_040_OR_060) | ||
437 | /* Now it seems to be safe to turn of the tt0 transparent | ||
438 | * translation (the one that must not be turned off in | ||
439 | * head.S...) | ||
440 | */ | ||
441 | __asm__ volatile ("moveq #0,%/d0\n\t" | ||
442 | ".chip 68040\n\t" | ||
443 | "movec %%d0,%%itt0\n\t" | ||
444 | "movec %%d0,%%dtt0\n\t" | ||
445 | ".chip 68k" | ||
446 | : /* no outputs */ | ||
447 | : /* no inputs */ | ||
448 | : "d0"); | ||
449 | |||
450 | /* allocator for memory that must reside in st-ram */ | ||
451 | atari_stram_init (); | ||
452 | |||
453 | /* Set up a mapping for the VMEbus address region: | ||
454 | * | ||
455 | * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff | ||
456 | * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at | ||
457 | * 0xfe000000 virt., because this can be done with a single | ||
458 | * transparent translation. On the 68040, lots of often unused | ||
459 | * page tables would be needed otherwise. On a MegaSTE or similar, | ||
460 | * the highest byte is stripped off by hardware due to the 24 bit | ||
461 | * design of the bus. | ||
462 | */ | ||
463 | |||
464 | if (CPU_IS_020_OR_030) { | ||
465 | unsigned long tt1_val; | ||
466 | tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache | ||
467 | * inhibit, read and write, FDC mask = 3, | ||
468 | * FDC val = 4 -> Supervisor only */ | ||
469 | __asm__ __volatile__ ( ".chip 68030\n\t" | ||
470 | "pmove %0@,%/tt1\n\t" | ||
471 | ".chip 68k" | ||
472 | : : "a" (&tt1_val) ); | ||
473 | } | ||
474 | else { | ||
475 | __asm__ __volatile__ | ||
476 | ( "movel %0,%/d0\n\t" | ||
477 | ".chip 68040\n\t" | ||
478 | "movec %%d0,%%itt1\n\t" | ||
479 | "movec %%d0,%%dtt1\n\t" | ||
480 | ".chip 68k" | ||
481 | : | ||
482 | : "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable, | ||
483 | * supervisor only, non-cacheable/ | ||
484 | * serialized, writable */ | ||
485 | : "d0" ); | ||
486 | |||
487 | } | ||
488 | |||
489 | /* Fetch tos version at Physical 2 */ | ||
490 | /* We my not be able to access this address if the kernel is | ||
491 | loaded to st ram, since the first page is unmapped. On the | ||
492 | Medusa this is always the case and there is nothing we can do | ||
493 | about this, so we just assume the smaller offset. For the TT | ||
494 | we use the fact that in head.S we have set up a mapping | ||
495 | 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible | ||
496 | in the last 16MB of the address space. */ | ||
497 | tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? | ||
498 | 0xfff : *(unsigned short *)0xff000002; | ||
499 | atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; | ||
500 | } | ||
501 | |||
502 | #ifdef CONFIG_HEARTBEAT | ||
503 | static void atari_heartbeat( int on ) | ||
504 | { | ||
505 | unsigned char tmp; | ||
506 | unsigned long flags; | ||
507 | |||
508 | if (atari_dont_touch_floppy_select) | ||
509 | return; | ||
510 | |||
511 | local_irq_save(flags); | ||
512 | sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ | ||
513 | tmp = sound_ym.rd_data_reg_sel; | ||
514 | sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); | ||
515 | local_irq_restore(flags); | ||
516 | } | ||
517 | #endif | ||
518 | |||
519 | /* ++roman: | ||
520 | * | ||
521 | * This function does a reset on machines that lack the ability to | ||
522 | * assert the processor's _RESET signal somehow via hardware. It is | ||
523 | * based on the fact that you can find the initial SP and PC values | ||
524 | * after a reset at physical addresses 0 and 4. This works pretty well | ||
525 | * for Atari machines, since the lowest 8 bytes of physical memory are | ||
526 | * really ROM (mapped by hardware). For other 680x0 machines: don't | ||
527 | * know if it works... | ||
528 | * | ||
529 | * To get the values at addresses 0 and 4, the MMU better is turned | ||
530 | * off first. After that, we have to jump into physical address space | ||
531 | * (the PC before the pmove statement points to the virtual address of | ||
532 | * the code). Getting that physical address is not hard, but the code | ||
533 | * becomes a bit complex since I've tried to ensure that the jump | ||
534 | * statement after the pmove is in the cache already (otherwise the | ||
535 | * processor can't fetch it!). For that, the code first jumps to the | ||
536 | * jump statement with the (virtual) address of the pmove section in | ||
537 | * an address register . The jump statement is surely in the cache | ||
538 | * now. After that, that physical address of the reset code is loaded | ||
539 | * into the same address register, pmove is done and the same jump | ||
540 | * statements goes to the reset code. Since there are not many | ||
541 | * statements between the two jumps, I hope it stays in the cache. | ||
542 | * | ||
543 | * The C code makes heavy use of the GCC features that you can get the | ||
544 | * address of a C label. No hope to compile this with another compiler | ||
545 | * than GCC! | ||
546 | */ | ||
547 | |||
548 | /* ++andreas: no need for complicated code, just depend on prefetch */ | ||
549 | |||
550 | static void atari_reset (void) | ||
551 | { | ||
552 | long tc_val = 0; | ||
553 | long reset_addr; | ||
554 | |||
555 | /* On the Medusa, phys. 0x4 may contain garbage because it's no | ||
556 | ROM. See above for explanation why we cannot use PTOV(4). */ | ||
557 | reset_addr = MACH_IS_HADES ? 0x7fe00030 : | ||
558 | MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : | ||
559 | *(unsigned long *) 0xff000004; | ||
560 | |||
561 | /* reset ACIA for switch off OverScan, if it's active */ | ||
562 | if (atari_switches & ATARI_SWITCH_OVSC_IKBD) | ||
563 | acia.key_ctrl = ACIA_RESET; | ||
564 | if (atari_switches & ATARI_SWITCH_OVSC_MIDI) | ||
565 | acia.mid_ctrl = ACIA_RESET; | ||
566 | |||
567 | /* processor independent: turn off interrupts and reset the VBR; | ||
568 | * the caches must be left enabled, else prefetching the final jump | ||
569 | * instruction doesn't work. */ | ||
570 | local_irq_disable(); | ||
571 | __asm__ __volatile__ | ||
572 | ("moveq #0,%/d0\n\t" | ||
573 | "movec %/d0,%/vbr" | ||
574 | : : : "d0" ); | ||
575 | |||
576 | if (CPU_IS_040_OR_060) { | ||
577 | unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); | ||
578 | if (CPU_IS_060) { | ||
579 | /* 68060: clear PCR to turn off superscalar operation */ | ||
580 | __asm__ __volatile__ | ||
581 | ("moveq #0,%/d0\n\t" | ||
582 | ".chip 68060\n\t" | ||
583 | "movec %%d0,%%pcr\n\t" | ||
584 | ".chip 68k" | ||
585 | : : : "d0" ); | ||
586 | } | ||
587 | |||
588 | __asm__ __volatile__ | ||
589 | ("movel %0,%/d0\n\t" | ||
590 | "andl #0xff000000,%/d0\n\t" | ||
591 | "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ | ||
592 | ".chip 68040\n\t" | ||
593 | "movec %%d0,%%itt0\n\t" | ||
594 | "movec %%d0,%%dtt0\n\t" | ||
595 | ".chip 68k\n\t" | ||
596 | "jmp %0@\n\t" | ||
597 | : /* no outputs */ | ||
598 | : "a" (jmp_addr040) | ||
599 | : "d0" ); | ||
600 | jmp_addr_label040: | ||
601 | __asm__ __volatile__ | ||
602 | ("moveq #0,%/d0\n\t" | ||
603 | "nop\n\t" | ||
604 | ".chip 68040\n\t" | ||
605 | "cinva %%bc\n\t" | ||
606 | "nop\n\t" | ||
607 | "pflusha\n\t" | ||
608 | "nop\n\t" | ||
609 | "movec %%d0,%%tc\n\t" | ||
610 | "nop\n\t" | ||
611 | /* the following setup of transparent translations is needed on the | ||
612 | * Afterburner040 to successfully reboot. Other machines shouldn't | ||
613 | * care about a different tt regs setup, they also didn't care in | ||
614 | * the past that the regs weren't turned off. */ | ||
615 | "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */ | ||
616 | "movec %%d0,%%itt0\n\t" | ||
617 | "movec %%d0,%%itt1\n\t" | ||
618 | "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */ | ||
619 | "movec %%d0,%%dtt0\n\t" | ||
620 | "movec %%d0,%%dtt1\n\t" | ||
621 | ".chip 68k\n\t" | ||
622 | "jmp %0@" | ||
623 | : /* no outputs */ | ||
624 | : "a" (reset_addr) | ||
625 | : "d0"); | ||
626 | } | ||
627 | else | ||
628 | __asm__ __volatile__ | ||
629 | ("pmove %0@,%/tc\n\t" | ||
630 | "jmp %1@" | ||
631 | : /* no outputs */ | ||
632 | : "a" (&tc_val), "a" (reset_addr)); | ||
633 | } | ||
634 | |||
635 | |||
636 | static void atari_get_model(char *model) | ||
637 | { | ||
638 | strcpy(model, "Atari "); | ||
639 | switch (atari_mch_cookie >> 16) { | ||
640 | case ATARI_MCH_ST: | ||
641 | if (ATARIHW_PRESENT(MSTE_CLK)) | ||
642 | strcat (model, "Mega ST"); | ||
643 | else | ||
644 | strcat (model, "ST"); | ||
645 | break; | ||
646 | case ATARI_MCH_STE: | ||
647 | if (MACH_IS_MSTE) | ||
648 | strcat (model, "Mega STE"); | ||
649 | else | ||
650 | strcat (model, "STE"); | ||
651 | break; | ||
652 | case ATARI_MCH_TT: | ||
653 | if (MACH_IS_MEDUSA) | ||
654 | /* Medusa has TT _MCH cookie */ | ||
655 | strcat (model, "Medusa"); | ||
656 | else if (MACH_IS_HADES) | ||
657 | strcat(model, "Hades"); | ||
658 | else | ||
659 | strcat (model, "TT"); | ||
660 | break; | ||
661 | case ATARI_MCH_FALCON: | ||
662 | strcat (model, "Falcon"); | ||
663 | if (MACH_IS_AB40) | ||
664 | strcat (model, " (with Afterburner040)"); | ||
665 | break; | ||
666 | default: | ||
667 | sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", | ||
668 | atari_mch_cookie); | ||
669 | break; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | |||
674 | static int atari_get_hardware_list(char *buffer) | ||
675 | { | ||
676 | int len = 0, i; | ||
677 | |||
678 | for (i = 0; i < m68k_num_memory; i++) | ||
679 | len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", | ||
680 | m68k_memory[i].size >> 20, m68k_memory[i].addr, | ||
681 | (m68k_memory[i].addr & 0xff000000 ? | ||
682 | "alternate RAM" : "ST-RAM")); | ||
683 | |||
684 | #define ATARIHW_ANNOUNCE(name,str) \ | ||
685 | if (ATARIHW_PRESENT(name)) \ | ||
686 | len += sprintf (buffer + len, "\t%s\n", str) | ||
687 | |||
688 | len += sprintf (buffer + len, "Detected hardware:\n"); | ||
689 | ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter"); | ||
690 | ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter"); | ||
691 | ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter"); | ||
692 | ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter"); | ||
693 | ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator"); | ||
694 | ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound"); | ||
695 | ATARIHW_ANNOUNCE(CODEC, "CODEC Sound"); | ||
696 | ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)"); | ||
697 | ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)"); | ||
698 | ATARIHW_ANNOUNCE(ACSI, "ACSI Interface"); | ||
699 | ATARIHW_ANNOUNCE(IDE, "IDE Interface"); | ||
700 | ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC"); | ||
701 | ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901"); | ||
702 | ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901"); | ||
703 | ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530"); | ||
704 | ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230"); | ||
705 | ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface"); | ||
706 | ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface"); | ||
707 | ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)"); | ||
708 | ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)"); | ||
709 | ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380"); | ||
710 | ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC"); | ||
711 | ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A"); | ||
712 | ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15"); | ||
713 | ATARIHW_ANNOUNCE(SCU, "System Control Unit"); | ||
714 | ATARIHW_ANNOUNCE(BLITTER, "Blitter"); | ||
715 | ATARIHW_ANNOUNCE(VME, "VME Bus"); | ||
716 | ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor"); | ||
717 | |||
718 | return(len); | ||
719 | } | ||
720 | |||
721 | /* | ||
722 | * Local variables: | ||
723 | * c-indent-level: 4 | ||
724 | * tab-width: 8 | ||
725 | * End: | ||
726 | */ | ||
diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c new file mode 100644 index 000000000000..ace05f79d968 --- /dev/null +++ b/arch/m68k/atari/debug.c | |||
@@ -0,0 +1,347 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/atari/debug.c | ||
3 | * | ||
4 | * Atari debugging and serial console stuff | ||
5 | * | ||
6 | * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek | ||
7 | * | ||
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 | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/tty.h> | ||
16 | #include <linux/console.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | #include <asm/atarihw.h> | ||
21 | #include <asm/atariints.h> | ||
22 | |||
23 | extern char m68k_debug_device[]; | ||
24 | |||
25 | /* Flag that Modem1 port is already initialized and used */ | ||
26 | int atari_MFP_init_done; | ||
27 | /* Flag that Modem1 port is already initialized and used */ | ||
28 | int atari_SCC_init_done; | ||
29 | /* Can be set somewhere, if a SCC master reset has already be done and should | ||
30 | * not be repeated; used by kgdb */ | ||
31 | int atari_SCC_reset_done; | ||
32 | |||
33 | static struct console atari_console_driver = { | ||
34 | .name = "debug", | ||
35 | .flags = CON_PRINTBUFFER, | ||
36 | .index = -1, | ||
37 | }; | ||
38 | |||
39 | |||
40 | static inline void ata_mfp_out (char c) | ||
41 | { | ||
42 | while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ | ||
43 | barrier (); | ||
44 | mfp.usart_dta = c; | ||
45 | } | ||
46 | |||
47 | void atari_mfp_console_write (struct console *co, const char *str, | ||
48 | unsigned int count) | ||
49 | { | ||
50 | while (count--) { | ||
51 | if (*str == '\n') | ||
52 | ata_mfp_out( '\r' ); | ||
53 | ata_mfp_out( *str++ ); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | static inline void ata_scc_out (char c) | ||
58 | { | ||
59 | do { | ||
60 | MFPDELAY(); | ||
61 | } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ | ||
62 | MFPDELAY(); | ||
63 | scc.cha_b_data = c; | ||
64 | } | ||
65 | |||
66 | void atari_scc_console_write (struct console *co, const char *str, | ||
67 | unsigned int count) | ||
68 | { | ||
69 | while (count--) { | ||
70 | if (*str == '\n') | ||
71 | ata_scc_out( '\r' ); | ||
72 | ata_scc_out( *str++ ); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static inline void ata_midi_out (char c) | ||
77 | { | ||
78 | while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ | ||
79 | barrier (); | ||
80 | acia.mid_data = c; | ||
81 | } | ||
82 | |||
83 | void atari_midi_console_write (struct console *co, const char *str, | ||
84 | unsigned int count) | ||
85 | { | ||
86 | while (count--) { | ||
87 | if (*str == '\n') | ||
88 | ata_midi_out( '\r' ); | ||
89 | ata_midi_out( *str++ ); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static int ata_par_out (char c) | ||
94 | { | ||
95 | unsigned char tmp; | ||
96 | /* This a some-seconds timeout in case no printer is connected */ | ||
97 | unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ; | ||
98 | |||
99 | while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ | ||
100 | ; | ||
101 | if (!i) return( 0 ); | ||
102 | |||
103 | sound_ym.rd_data_reg_sel = 15; /* select port B */ | ||
104 | sound_ym.wd_data = c; /* put char onto port */ | ||
105 | sound_ym.rd_data_reg_sel = 14; /* select port A */ | ||
106 | tmp = sound_ym.rd_data_reg_sel; | ||
107 | sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ | ||
108 | MFPDELAY(); /* wait a bit */ | ||
109 | sound_ym.wd_data = tmp | 0x20; /* set strobe H */ | ||
110 | return( 1 ); | ||
111 | } | ||
112 | |||
113 | static void atari_par_console_write (struct console *co, const char *str, | ||
114 | unsigned int count) | ||
115 | { | ||
116 | static int printer_present = 1; | ||
117 | |||
118 | if (!printer_present) | ||
119 | return; | ||
120 | |||
121 | while (count--) { | ||
122 | if (*str == '\n') | ||
123 | if (!ata_par_out( '\r' )) { | ||
124 | printer_present = 0; | ||
125 | return; | ||
126 | } | ||
127 | if (!ata_par_out( *str++ )) { | ||
128 | printer_present = 0; | ||
129 | return; | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | #ifdef CONFIG_SERIAL_CONSOLE | ||
135 | int atari_mfp_console_wait_key(struct console *co) | ||
136 | { | ||
137 | while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */ | ||
138 | barrier(); | ||
139 | return( mfp.usart_dta ); | ||
140 | } | ||
141 | |||
142 | int atari_scc_console_wait_key(struct console *co) | ||
143 | { | ||
144 | do { | ||
145 | MFPDELAY(); | ||
146 | } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ | ||
147 | MFPDELAY(); | ||
148 | return( scc.cha_b_data ); | ||
149 | } | ||
150 | |||
151 | int atari_midi_console_wait_key(struct console *co) | ||
152 | { | ||
153 | while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */ | ||
154 | barrier(); | ||
155 | return( acia.mid_data ); | ||
156 | } | ||
157 | #endif | ||
158 | |||
159 | /* The following two functions do a quick'n'dirty initialization of the MFP or | ||
160 | * SCC serial ports. They're used by the debugging interface, kgdb, and the | ||
161 | * serial console code. */ | ||
162 | #ifndef CONFIG_SERIAL_CONSOLE | ||
163 | static void __init atari_init_mfp_port( int cflag ) | ||
164 | #else | ||
165 | void atari_init_mfp_port( int cflag ) | ||
166 | #endif | ||
167 | { | ||
168 | /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 | ||
169 | * bps, resp., and work only correct if there's a RSVE or RSSPEED */ | ||
170 | static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; | ||
171 | int baud = cflag & CBAUD; | ||
172 | int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; | ||
173 | int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; | ||
174 | |||
175 | if (cflag & CBAUDEX) | ||
176 | baud += B38400; | ||
177 | if (baud < B1200 || baud > B38400+2) | ||
178 | baud = B9600; /* use default 9600bps for non-implemented rates */ | ||
179 | baud -= B1200; /* baud_table[] starts at 1200bps */ | ||
180 | |||
181 | mfp.trn_stat &= ~0x01; /* disable TX */ | ||
182 | mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ | ||
183 | mfp.tim_ct_cd &= 0x70; /* stop timer D */ | ||
184 | mfp.tim_dt_d = baud_table[baud]; | ||
185 | mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ | ||
186 | mfp.trn_stat |= 0x01; /* enable TX */ | ||
187 | |||
188 | atari_MFP_init_done = 1; | ||
189 | } | ||
190 | |||
191 | #define SCC_WRITE(reg,val) \ | ||
192 | do { \ | ||
193 | scc.cha_b_ctrl = (reg); \ | ||
194 | MFPDELAY(); \ | ||
195 | scc.cha_b_ctrl = (val); \ | ||
196 | MFPDELAY(); \ | ||
197 | } while(0) | ||
198 | |||
199 | /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a | ||
200 | * delay of ~ 60us. */ | ||
201 | #define LONG_DELAY() \ | ||
202 | do { \ | ||
203 | int i; \ | ||
204 | for( i = 100; i > 0; --i ) \ | ||
205 | MFPDELAY(); \ | ||
206 | } while(0) | ||
207 | |||
208 | #ifndef CONFIG_SERIAL_CONSOLE | ||
209 | static void __init atari_init_scc_port( int cflag ) | ||
210 | #else | ||
211 | void atari_init_scc_port( int cflag ) | ||
212 | #endif | ||
213 | { | ||
214 | extern int atari_SCC_reset_done; | ||
215 | static int clksrc_table[9] = | ||
216 | /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ | ||
217 | { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; | ||
218 | static int brgsrc_table[9] = | ||
219 | /* reg 14: 0 = RTxC, 2 = PCLK */ | ||
220 | { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; | ||
221 | static int clkmode_table[9] = | ||
222 | /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ | ||
223 | { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; | ||
224 | static int div_table[9] = | ||
225 | /* reg12 (BRG low) */ | ||
226 | { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; | ||
227 | |||
228 | int baud = cflag & CBAUD; | ||
229 | int clksrc, clkmode, div, reg3, reg5; | ||
230 | |||
231 | if (cflag & CBAUDEX) | ||
232 | baud += B38400; | ||
233 | if (baud < B1200 || baud > B38400+2) | ||
234 | baud = B9600; /* use default 9600bps for non-implemented rates */ | ||
235 | baud -= B1200; /* tables starts at 1200bps */ | ||
236 | |||
237 | clksrc = clksrc_table[baud]; | ||
238 | clkmode = clkmode_table[baud]; | ||
239 | div = div_table[baud]; | ||
240 | if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { | ||
241 | /* special treatment for TT, where rates >= 38400 are done via TRxC */ | ||
242 | clksrc = 0x28; /* TRxC */ | ||
243 | clkmode = baud == 6 ? 0xc0 : | ||
244 | baud == 7 ? 0x80 : /* really 76800bps */ | ||
245 | 0x40; /* really 153600bps */ | ||
246 | div = 0; | ||
247 | } | ||
248 | |||
249 | reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; | ||
250 | reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; | ||
251 | |||
252 | (void)scc.cha_b_ctrl; /* reset reg pointer */ | ||
253 | SCC_WRITE( 9, 0xc0 ); /* reset */ | ||
254 | LONG_DELAY(); /* extra delay after WR9 access */ | ||
255 | SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | | ||
256 | 0x04 /* 1 stopbit */ | | ||
257 | clkmode ); | ||
258 | SCC_WRITE( 3, reg3 ); | ||
259 | SCC_WRITE( 5, reg5 ); | ||
260 | SCC_WRITE( 9, 0 ); /* no interrupts */ | ||
261 | LONG_DELAY(); /* extra delay after WR9 access */ | ||
262 | SCC_WRITE( 10, 0 ); /* NRZ mode */ | ||
263 | SCC_WRITE( 11, clksrc ); /* main clock source */ | ||
264 | SCC_WRITE( 12, div ); /* BRG value */ | ||
265 | SCC_WRITE( 13, 0 ); /* BRG high byte */ | ||
266 | SCC_WRITE( 14, brgsrc_table[baud] ); | ||
267 | SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); | ||
268 | SCC_WRITE( 3, reg3 | 1 ); | ||
269 | SCC_WRITE( 5, reg5 | 8 ); | ||
270 | |||
271 | atari_SCC_reset_done = 1; | ||
272 | atari_SCC_init_done = 1; | ||
273 | } | ||
274 | |||
275 | #ifndef CONFIG_SERIAL_CONSOLE | ||
276 | static void __init atari_init_midi_port( int cflag ) | ||
277 | #else | ||
278 | void atari_init_midi_port( int cflag ) | ||
279 | #endif | ||
280 | { | ||
281 | int baud = cflag & CBAUD; | ||
282 | int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; | ||
283 | /* warning 7N1 isn't possible! (instead 7O2 is used...) */ | ||
284 | int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; | ||
285 | int div; | ||
286 | |||
287 | /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as | ||
288 | * default) the standard MIDI speed 31250. */ | ||
289 | if (cflag & CBAUDEX) | ||
290 | baud += B38400; | ||
291 | if (baud == B4800) | ||
292 | div = ACIA_DIV64; /* really 7812.5 bps */ | ||
293 | else if (baud == B38400+2 /* 115200 */) | ||
294 | div = ACIA_DIV1; /* really 500 kbps (does that work??) */ | ||
295 | else | ||
296 | div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ | ||
297 | |||
298 | /* RTS low, ints disabled */ | ||
299 | acia.mid_ctrl = div | csize | parity | | ||
300 | ((atari_switches & ATARI_SWITCH_MIDI) ? | ||
301 | ACIA_RHTID : ACIA_RLTID); | ||
302 | } | ||
303 | |||
304 | void __init atari_debug_init(void) | ||
305 | { | ||
306 | if (!strcmp( m68k_debug_device, "ser" )) { | ||
307 | /* defaults to ser2 for a Falcon and ser1 otherwise */ | ||
308 | strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" ); | ||
309 | |||
310 | } | ||
311 | |||
312 | if (!strcmp( m68k_debug_device, "ser1" )) { | ||
313 | /* ST-MFP Modem1 serial port */ | ||
314 | atari_init_mfp_port( B9600|CS8 ); | ||
315 | atari_console_driver.write = atari_mfp_console_write; | ||
316 | } | ||
317 | else if (!strcmp( m68k_debug_device, "ser2" )) { | ||
318 | /* SCC Modem2 serial port */ | ||
319 | atari_init_scc_port( B9600|CS8 ); | ||
320 | atari_console_driver.write = atari_scc_console_write; | ||
321 | } | ||
322 | else if (!strcmp( m68k_debug_device, "midi" )) { | ||
323 | /* MIDI port */ | ||
324 | atari_init_midi_port( B9600|CS8 ); | ||
325 | atari_console_driver.write = atari_midi_console_write; | ||
326 | } | ||
327 | else if (!strcmp( m68k_debug_device, "par" )) { | ||
328 | /* parallel printer */ | ||
329 | atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ | ||
330 | sound_ym.rd_data_reg_sel = 7; /* select mixer control */ | ||
331 | sound_ym.wd_data = 0xff; /* sound off, ports are output */ | ||
332 | sound_ym.rd_data_reg_sel = 15; /* select port B */ | ||
333 | sound_ym.wd_data = 0; /* no char */ | ||
334 | sound_ym.rd_data_reg_sel = 14; /* select port A */ | ||
335 | sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ | ||
336 | atari_console_driver.write = atari_par_console_write; | ||
337 | } | ||
338 | if (atari_console_driver.write) | ||
339 | register_console(&atari_console_driver); | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * Local variables: | ||
344 | * c-indent-level: 4 | ||
345 | * tab-width: 8 | ||
346 | * End: | ||
347 | */ | ||
diff --git a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c new file mode 100644 index 000000000000..8888debf71ec --- /dev/null +++ b/arch/m68k/atari/hades-pci.c | |||
@@ -0,0 +1,444 @@ | |||
1 | /* | ||
2 | * hades-pci.c - Hardware specific PCI BIOS functions the Hades Atari clone. | ||
3 | * | ||
4 | * Written by Wout Klaren. | ||
5 | */ | ||
6 | |||
7 | #include <linux/config.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <asm/io.h> | ||
11 | |||
12 | #if 0 | ||
13 | # define DBG_DEVS(args) printk args | ||
14 | #else | ||
15 | # define DBG_DEVS(args) | ||
16 | #endif | ||
17 | |||
18 | #if defined(CONFIG_PCI) && defined(CONFIG_HADES) | ||
19 | |||
20 | #include <linux/slab.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/pci.h> | ||
23 | |||
24 | #include <asm/atarihw.h> | ||
25 | #include <asm/atariints.h> | ||
26 | #include <asm/byteorder.h> | ||
27 | #include <asm/pci.h> | ||
28 | |||
29 | #define HADES_MEM_BASE 0x80000000 | ||
30 | #define HADES_MEM_SIZE 0x20000000 | ||
31 | #define HADES_CONFIG_BASE 0xA0000000 | ||
32 | #define HADES_CONFIG_SIZE 0x10000000 | ||
33 | #define HADES_IO_BASE 0xB0000000 | ||
34 | #define HADES_IO_SIZE 0x10000000 | ||
35 | #define HADES_VIRT_IO_SIZE 0x00010000 /* Only 64k is remapped and actually used. */ | ||
36 | |||
37 | #define N_SLOTS 4 /* Number of PCI slots. */ | ||
38 | |||
39 | static const char pci_mem_name[] = "PCI memory space"; | ||
40 | static const char pci_io_name[] = "PCI I/O space"; | ||
41 | static const char pci_config_name[] = "PCI config space"; | ||
42 | |||
43 | static struct resource config_space = { | ||
44 | .name = pci_config_name, | ||
45 | .start = HADES_CONFIG_BASE, | ||
46 | .end = HADES_CONFIG_BASE + HADES_CONFIG_SIZE - 1 | ||
47 | }; | ||
48 | static struct resource io_space = { | ||
49 | .name = pci_io_name, | ||
50 | .start = HADES_IO_BASE, | ||
51 | .end = HADES_IO_BASE + HADES_IO_SIZE - 1 | ||
52 | }; | ||
53 | |||
54 | static const unsigned long pci_conf_base_phys[] = { | ||
55 | 0xA0080000, 0xA0040000, 0xA0020000, 0xA0010000 | ||
56 | }; | ||
57 | static unsigned long pci_conf_base_virt[N_SLOTS]; | ||
58 | static unsigned long pci_io_base_virt; | ||
59 | |||
60 | /* | ||
61 | * static void *mk_conf_addr(unsigned char bus, unsigned char device_fn, | ||
62 | * unsigned char where) | ||
63 | * | ||
64 | * Calculate the address of the PCI configuration area of the given | ||
65 | * device. | ||
66 | * | ||
67 | * BUG: boards with multiple functions are probably not correctly | ||
68 | * supported. | ||
69 | */ | ||
70 | |||
71 | static void *mk_conf_addr(struct pci_dev *dev, int where) | ||
72 | { | ||
73 | int device = dev->devfn >> 3, function = dev->devfn & 7; | ||
74 | void *result; | ||
75 | |||
76 | DBG_DEVS(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p)\n", | ||
77 | dev->bus->number, dev->devfn, where, pci_addr)); | ||
78 | |||
79 | if (device > 3) | ||
80 | { | ||
81 | DBG_DEVS(("mk_conf_addr: device (%d) > 3, returning NULL\n", device)); | ||
82 | return NULL; | ||
83 | } | ||
84 | |||
85 | if (dev->bus->number != 0) | ||
86 | { | ||
87 | DBG_DEVS(("mk_conf_addr: bus (%d) > 0, returning NULL\n", device)); | ||
88 | return NULL; | ||
89 | } | ||
90 | |||
91 | result = (void *) (pci_conf_base_virt[device] | (function << 8) | (where)); | ||
92 | DBG_DEVS(("mk_conf_addr: returning pci_addr 0x%lx\n", (unsigned long) result)); | ||
93 | return result; | ||
94 | } | ||
95 | |||
96 | static int hades_read_config_byte(struct pci_dev *dev, int where, u8 *value) | ||
97 | { | ||
98 | volatile unsigned char *pci_addr; | ||
99 | |||
100 | *value = 0xff; | ||
101 | |||
102 | if ((pci_addr = (unsigned char *) mk_conf_addr(dev, where)) == NULL) | ||
103 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
104 | |||
105 | *value = *pci_addr; | ||
106 | |||
107 | return PCIBIOS_SUCCESSFUL; | ||
108 | } | ||
109 | |||
110 | static int hades_read_config_word(struct pci_dev *dev, int where, u16 *value) | ||
111 | { | ||
112 | volatile unsigned short *pci_addr; | ||
113 | |||
114 | *value = 0xffff; | ||
115 | |||
116 | if (where & 0x1) | ||
117 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
118 | |||
119 | if ((pci_addr = (unsigned short *) mk_conf_addr(dev, where)) == NULL) | ||
120 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
121 | |||
122 | *value = le16_to_cpu(*pci_addr); | ||
123 | |||
124 | return PCIBIOS_SUCCESSFUL; | ||
125 | } | ||
126 | |||
127 | static int hades_read_config_dword(struct pci_dev *dev, int where, u32 *value) | ||
128 | { | ||
129 | volatile unsigned int *pci_addr; | ||
130 | unsigned char header_type; | ||
131 | int result; | ||
132 | |||
133 | *value = 0xffffffff; | ||
134 | |||
135 | if (where & 0x3) | ||
136 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
137 | |||
138 | if ((pci_addr = (unsigned int *) mk_conf_addr(dev, where)) == NULL) | ||
139 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
140 | |||
141 | *value = le32_to_cpu(*pci_addr); | ||
142 | |||
143 | /* | ||
144 | * Check if the value is an address on the bus. If true, add the | ||
145 | * base address of the PCI memory or PCI I/O area on the Hades. | ||
146 | */ | ||
147 | |||
148 | if ((result = hades_read_config_byte(dev, PCI_HEADER_TYPE, | ||
149 | &header_type)) != PCIBIOS_SUCCESSFUL) | ||
150 | return result; | ||
151 | |||
152 | if (((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_1)) || | ||
153 | ((header_type != PCI_HEADER_TYPE_BRIDGE) && ((where >= PCI_BASE_ADDRESS_2) && | ||
154 | (where <= PCI_BASE_ADDRESS_5)))) | ||
155 | { | ||
156 | if ((*value & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) | ||
157 | { | ||
158 | /* | ||
159 | * Base address register that contains an I/O address. If the | ||
160 | * address is valid on the Hades (0 <= *value < HADES_VIRT_IO_SIZE), | ||
161 | * add 'pci_io_base_virt' to the value. | ||
162 | */ | ||
163 | |||
164 | if (*value < HADES_VIRT_IO_SIZE) | ||
165 | *value += pci_io_base_virt; | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | /* | ||
170 | * Base address register that contains an memory address. If the | ||
171 | * address is valid on the Hades (0 <= *value < HADES_MEM_SIZE), | ||
172 | * add HADES_MEM_BASE to the value. | ||
173 | */ | ||
174 | |||
175 | if (*value == 0) | ||
176 | { | ||
177 | /* | ||
178 | * Base address is 0. Test if this base | ||
179 | * address register is used. | ||
180 | */ | ||
181 | |||
182 | *pci_addr = 0xffffffff; | ||
183 | if (*pci_addr != 0) | ||
184 | { | ||
185 | *pci_addr = *value; | ||
186 | if (*value < HADES_MEM_SIZE) | ||
187 | *value += HADES_MEM_BASE; | ||
188 | } | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | if (*value < HADES_MEM_SIZE) | ||
193 | *value += HADES_MEM_BASE; | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
198 | return PCIBIOS_SUCCESSFUL; | ||
199 | } | ||
200 | |||
201 | static int hades_write_config_byte(struct pci_dev *dev, int where, u8 value) | ||
202 | { | ||
203 | volatile unsigned char *pci_addr; | ||
204 | |||
205 | if ((pci_addr = (unsigned char *) mk_conf_addr(dev, where)) == NULL) | ||
206 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
207 | |||
208 | *pci_addr = value; | ||
209 | |||
210 | return PCIBIOS_SUCCESSFUL; | ||
211 | } | ||
212 | |||
213 | static int hades_write_config_word(struct pci_dev *dev, int where, u16 value) | ||
214 | { | ||
215 | volatile unsigned short *pci_addr; | ||
216 | |||
217 | if ((pci_addr = (unsigned short *) mk_conf_addr(dev, where)) == NULL) | ||
218 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
219 | |||
220 | *pci_addr = cpu_to_le16(value); | ||
221 | |||
222 | return PCIBIOS_SUCCESSFUL; | ||
223 | } | ||
224 | |||
225 | static int hades_write_config_dword(struct pci_dev *dev, int where, u32 value) | ||
226 | { | ||
227 | volatile unsigned int *pci_addr; | ||
228 | unsigned char header_type; | ||
229 | int result; | ||
230 | |||
231 | if ((pci_addr = (unsigned int *) mk_conf_addr(dev, where)) == NULL) | ||
232 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
233 | |||
234 | /* | ||
235 | * Check if the value is an address on the bus. If true, subtract the | ||
236 | * base address of the PCI memory or PCI I/O area on the Hades. | ||
237 | */ | ||
238 | |||
239 | if ((result = hades_read_config_byte(dev, PCI_HEADER_TYPE, | ||
240 | &header_type)) != PCIBIOS_SUCCESSFUL) | ||
241 | return result; | ||
242 | |||
243 | if (((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_1)) || | ||
244 | ((header_type != PCI_HEADER_TYPE_BRIDGE) && ((where >= PCI_BASE_ADDRESS_2) && | ||
245 | (where <= PCI_BASE_ADDRESS_5)))) | ||
246 | { | ||
247 | if ((value & PCI_BASE_ADDRESS_SPACE) == | ||
248 | PCI_BASE_ADDRESS_SPACE_IO) | ||
249 | { | ||
250 | /* | ||
251 | * I/O address. Check if the address is valid address on | ||
252 | * the Hades (pci_io_base_virt <= value < pci_io_base_virt + | ||
253 | * HADES_VIRT_IO_SIZE) or if the value is 0xffffffff. If not | ||
254 | * true do not write the base address register. If it is a | ||
255 | * valid base address subtract 'pci_io_base_virt' from the value. | ||
256 | */ | ||
257 | |||
258 | if ((value >= pci_io_base_virt) && (value < (pci_io_base_virt + | ||
259 | HADES_VIRT_IO_SIZE))) | ||
260 | value -= pci_io_base_virt; | ||
261 | else | ||
262 | { | ||
263 | if (value != 0xffffffff) | ||
264 | return PCIBIOS_SET_FAILED; | ||
265 | } | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | /* | ||
270 | * Memory address. Check if the address is valid address on | ||
271 | * the Hades (HADES_MEM_BASE <= value < HADES_MEM_BASE + HADES_MEM_SIZE) or | ||
272 | * if the value is 0xffffffff. If not true do not write | ||
273 | * the base address register. If it is a valid base address | ||
274 | * subtract HADES_MEM_BASE from the value. | ||
275 | */ | ||
276 | |||
277 | if ((value >= HADES_MEM_BASE) && (value < (HADES_MEM_BASE + HADES_MEM_SIZE))) | ||
278 | value -= HADES_MEM_BASE; | ||
279 | else | ||
280 | { | ||
281 | if (value != 0xffffffff) | ||
282 | return PCIBIOS_SET_FAILED; | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | *pci_addr = cpu_to_le32(value); | ||
288 | |||
289 | return PCIBIOS_SUCCESSFUL; | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * static inline void hades_fixup(void) | ||
294 | * | ||
295 | * Assign IRQ numbers as used by Linux to the interrupt pins | ||
296 | * of the PCI cards. | ||
297 | */ | ||
298 | |||
299 | static void __init hades_fixup(int pci_modify) | ||
300 | { | ||
301 | char irq_tab[4] = { | ||
302 | [0] = IRQ_TT_MFP_IO0, /* Slot 0. */ | ||
303 | [1] = IRQ_TT_MFP_IO1, /* Slot 1. */ | ||
304 | [2] = IRQ_TT_MFP_SCC, /* Slot 2. */ | ||
305 | [3] = IRQ_TT_MFP_SCSIDMA /* Slot 3. */ | ||
306 | }; | ||
307 | struct pci_dev *dev = NULL; | ||
308 | unsigned char slot; | ||
309 | |||
310 | /* | ||
311 | * Go through all devices, fixing up irqs as we see fit: | ||
312 | */ | ||
313 | |||
314 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) | ||
315 | { | ||
316 | if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) | ||
317 | { | ||
318 | slot = PCI_SLOT(dev->devfn); /* Determine slot number. */ | ||
319 | dev->irq = irq_tab[slot]; | ||
320 | if (pci_modify) | ||
321 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | |||
326 | /* | ||
327 | * static void hades_conf_device(struct pci_dev *dev) | ||
328 | * | ||
329 | * Machine dependent Configure the given device. | ||
330 | * | ||
331 | * Parameters: | ||
332 | * | ||
333 | * dev - the pci device. | ||
334 | */ | ||
335 | |||
336 | static void __init hades_conf_device(struct pci_dev *dev) | ||
337 | { | ||
338 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0); | ||
339 | } | ||
340 | |||
341 | static struct pci_ops hades_pci_ops = { | ||
342 | .read_byte = hades_read_config_byte, | ||
343 | .read_word = hades_read_config_word, | ||
344 | .read_dword = hades_read_config_dword, | ||
345 | .write_byte = hades_write_config_byte, | ||
346 | .write_word = hades_write_config_word, | ||
347 | .write_dword = hades_write_config_dword | ||
348 | }; | ||
349 | |||
350 | /* | ||
351 | * struct pci_bus_info *init_hades_pci(void) | ||
352 | * | ||
353 | * Machine specific initialisation: | ||
354 | * | ||
355 | * - Allocate and initialise a 'pci_bus_info' structure | ||
356 | * - Initialise hardware | ||
357 | * | ||
358 | * Result: pointer to 'pci_bus_info' structure. | ||
359 | */ | ||
360 | |||
361 | struct pci_bus_info * __init init_hades_pci(void) | ||
362 | { | ||
363 | struct pci_bus_info *bus; | ||
364 | int i; | ||
365 | |||
366 | /* | ||
367 | * Remap I/O and configuration space. | ||
368 | */ | ||
369 | |||
370 | pci_io_base_virt = (unsigned long) ioremap(HADES_IO_BASE, HADES_VIRT_IO_SIZE); | ||
371 | |||
372 | for (i = 0; i < N_SLOTS; i++) | ||
373 | pci_conf_base_virt[i] = (unsigned long) ioremap(pci_conf_base_phys[i], 0x10000); | ||
374 | |||
375 | /* | ||
376 | * Allocate memory for bus info structure. | ||
377 | */ | ||
378 | |||
379 | bus = kmalloc(sizeof(struct pci_bus_info), GFP_KERNEL); | ||
380 | if (!bus) | ||
381 | return NULL; | ||
382 | memset(bus, 0, sizeof(struct pci_bus_info)); | ||
383 | |||
384 | /* | ||
385 | * Claim resources. The m68k has no separate I/O space, both | ||
386 | * PCI memory space and PCI I/O space are in memory space. Therefore | ||
387 | * the I/O resources are requested in memory space as well. | ||
388 | */ | ||
389 | |||
390 | if (request_resource(&iomem_resource, &config_space) != 0) | ||
391 | { | ||
392 | kfree(bus); | ||
393 | return NULL; | ||
394 | } | ||
395 | |||
396 | if (request_resource(&iomem_resource, &io_space) != 0) | ||
397 | { | ||
398 | release_resource(&config_space); | ||
399 | kfree(bus); | ||
400 | return NULL; | ||
401 | } | ||
402 | |||
403 | bus->mem_space.start = HADES_MEM_BASE; | ||
404 | bus->mem_space.end = HADES_MEM_BASE + HADES_MEM_SIZE - 1; | ||
405 | bus->mem_space.name = pci_mem_name; | ||
406 | #if 1 | ||
407 | if (request_resource(&iomem_resource, &bus->mem_space) != 0) | ||
408 | { | ||
409 | release_resource(&io_space); | ||
410 | release_resource(&config_space); | ||
411 | kfree(bus); | ||
412 | return NULL; | ||
413 | } | ||
414 | #endif | ||
415 | bus->io_space.start = pci_io_base_virt; | ||
416 | bus->io_space.end = pci_io_base_virt + HADES_VIRT_IO_SIZE - 1; | ||
417 | bus->io_space.name = pci_io_name; | ||
418 | #if 1 | ||
419 | if (request_resource(&ioport_resource, &bus->io_space) != 0) | ||
420 | { | ||
421 | release_resource(&bus->mem_space); | ||
422 | release_resource(&io_space); | ||
423 | release_resource(&config_space); | ||
424 | kfree(bus); | ||
425 | return NULL; | ||
426 | } | ||
427 | #endif | ||
428 | /* | ||
429 | * Set hardware dependent functions. | ||
430 | */ | ||
431 | |||
432 | bus->m68k_pci_ops = &hades_pci_ops; | ||
433 | bus->fixup = hades_fixup; | ||
434 | bus->conf_device = hades_conf_device; | ||
435 | |||
436 | /* | ||
437 | * Select high to low edge for PCI interrupts. | ||
438 | */ | ||
439 | |||
440 | tt_mfp.active_edge &= ~0x27; | ||
441 | |||
442 | return bus; | ||
443 | } | ||
444 | #endif | ||
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c new file mode 100644 index 000000000000..288f5e6a124e --- /dev/null +++ b/arch/m68k/atari/stdma.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/atari/stmda.c | ||
3 | * | ||
4 | * Copyright (C) 1994 Roman Hodek | ||
5 | * | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file COPYING in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | |||
12 | |||
13 | /* This file contains some function for controlling the access to the */ | ||
14 | /* ST-DMA chip that may be shared between devices. Currently we have: */ | ||
15 | /* TT: Floppy and ACSI bus */ | ||
16 | /* Falcon: Floppy and SCSI */ | ||
17 | /* */ | ||
18 | /* The controlling functions set up a wait queue for access to the */ | ||
19 | /* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */ | ||
20 | /* put onto a queue and waked up later if the owner calls */ | ||
21 | /* stdma_release(). Additionally, the caller gives his interrupt */ | ||
22 | /* service routine to stdma_lock(). */ | ||
23 | /* */ | ||
24 | /* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */ | ||
25 | /* not the ST-DMA chip itself. So falhd.c needs not to lock the */ | ||
26 | /* chip. The interrupt is routed to falhd.c if IDE is configured, the */ | ||
27 | /* model is a Falcon and the interrupt was caused by the HD controller */ | ||
28 | /* (can be determined by looking at its status register). */ | ||
29 | |||
30 | |||
31 | #include <linux/types.h> | ||
32 | #include <linux/kdev_t.h> | ||
33 | #include <linux/genhd.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/wait.h> | ||
38 | |||
39 | #include <asm/atari_stdma.h> | ||
40 | #include <asm/atariints.h> | ||
41 | #include <asm/atarihw.h> | ||
42 | #include <asm/io.h> | ||
43 | #include <asm/irq.h> | ||
44 | |||
45 | static int stdma_locked; /* the semaphore */ | ||
46 | /* int func to be called */ | ||
47 | static irqreturn_t (*stdma_isr)(int, void *, struct pt_regs *); | ||
48 | static void *stdma_isr_data; /* data passed to isr */ | ||
49 | static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ | ||
50 | |||
51 | |||
52 | |||
53 | |||
54 | /***************************** Prototypes *****************************/ | ||
55 | |||
56 | static irqreturn_t stdma_int (int irq, void *dummy, struct pt_regs *fp); | ||
57 | |||
58 | /************************* End of Prototypes **************************/ | ||
59 | |||
60 | |||
61 | |||
62 | /* | ||
63 | * Function: void stdma_lock( isrfunc isr, void *data ) | ||
64 | * | ||
65 | * Purpose: Tries to get a lock on the ST-DMA chip that is used by more | ||
66 | * then one device driver. Waits on stdma_wait until lock is free. | ||
67 | * stdma_lock() may not be called from an interrupt! You have to | ||
68 | * get the lock in your main routine and release it when your | ||
69 | * request is finished. | ||
70 | * | ||
71 | * Inputs: A interrupt function that is called until the lock is | ||
72 | * released. | ||
73 | * | ||
74 | * Returns: nothing | ||
75 | * | ||
76 | */ | ||
77 | |||
78 | void stdma_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
79 | void *data) | ||
80 | { | ||
81 | unsigned long flags; | ||
82 | |||
83 | local_irq_save(flags); /* protect lock */ | ||
84 | |||
85 | /* Since the DMA is used for file system purposes, we | ||
86 | have to sleep uninterruptible (there may be locked | ||
87 | buffers) */ | ||
88 | wait_event(stdma_wait, !stdma_locked); | ||
89 | |||
90 | stdma_locked = 1; | ||
91 | stdma_isr = handler; | ||
92 | stdma_isr_data = data; | ||
93 | local_irq_restore(flags); | ||
94 | } | ||
95 | |||
96 | |||
97 | /* | ||
98 | * Function: void stdma_release( void ) | ||
99 | * | ||
100 | * Purpose: Releases the lock on the ST-DMA chip. | ||
101 | * | ||
102 | * Inputs: none | ||
103 | * | ||
104 | * Returns: nothing | ||
105 | * | ||
106 | */ | ||
107 | |||
108 | void stdma_release(void) | ||
109 | { | ||
110 | unsigned long flags; | ||
111 | |||
112 | local_irq_save(flags); | ||
113 | |||
114 | stdma_locked = 0; | ||
115 | stdma_isr = NULL; | ||
116 | stdma_isr_data = NULL; | ||
117 | wake_up(&stdma_wait); | ||
118 | |||
119 | local_irq_restore(flags); | ||
120 | } | ||
121 | |||
122 | |||
123 | /* | ||
124 | * Function: int stdma_others_waiting( void ) | ||
125 | * | ||
126 | * Purpose: Check if someone waits for the ST-DMA lock. | ||
127 | * | ||
128 | * Inputs: none | ||
129 | * | ||
130 | * Returns: 0 if no one is waiting, != 0 otherwise | ||
131 | * | ||
132 | */ | ||
133 | |||
134 | int stdma_others_waiting(void) | ||
135 | { | ||
136 | return waitqueue_active(&stdma_wait); | ||
137 | } | ||
138 | |||
139 | |||
140 | /* | ||
141 | * Function: int stdma_islocked( void ) | ||
142 | * | ||
143 | * Purpose: Check if the ST-DMA is currently locked. | ||
144 | * Note: Returned status is only valid if ints are disabled while calling and | ||
145 | * as long as they remain disabled. | ||
146 | * If called with ints enabled, status can change only from locked to | ||
147 | * unlocked, because ints may not lock the ST-DMA. | ||
148 | * | ||
149 | * Inputs: none | ||
150 | * | ||
151 | * Returns: != 0 if locked, 0 otherwise | ||
152 | * | ||
153 | */ | ||
154 | |||
155 | int stdma_islocked(void) | ||
156 | { | ||
157 | return stdma_locked; | ||
158 | } | ||
159 | |||
160 | |||
161 | /* | ||
162 | * Function: void stdma_init( void ) | ||
163 | * | ||
164 | * Purpose: Initialize the ST-DMA chip access controlling. | ||
165 | * It sets up the interrupt and its service routine. The int is registered | ||
166 | * as slow int, client devices have to live with that (no problem | ||
167 | * currently). | ||
168 | * | ||
169 | * Inputs: none | ||
170 | * | ||
171 | * Return: nothing | ||
172 | * | ||
173 | */ | ||
174 | |||
175 | void __init stdma_init(void) | ||
176 | { | ||
177 | stdma_isr = NULL; | ||
178 | request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW, | ||
179 | "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int); | ||
180 | } | ||
181 | |||
182 | |||
183 | /* | ||
184 | * Function: void stdma_int() | ||
185 | * | ||
186 | * Purpose: The interrupt routine for the ST-DMA. It calls the isr | ||
187 | * registered by stdma_lock(). | ||
188 | * | ||
189 | */ | ||
190 | |||
191 | static irqreturn_t stdma_int(int irq, void *dummy, struct pt_regs *fp) | ||
192 | { | ||
193 | if (stdma_isr) | ||
194 | (*stdma_isr)(irq, stdma_isr_data, fp); | ||
195 | return IRQ_HANDLED; | ||
196 | } | ||
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c new file mode 100644 index 000000000000..5a3c106b40c8 --- /dev/null +++ b/arch/m68k/atari/stram.c | |||
@@ -0,0 +1,1247 @@ | |||
1 | /* | ||
2 | * arch/m68k/atari/stram.c: Functions for ST-RAM allocations | ||
3 | * | ||
4 | * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/mm.h> | ||
15 | #include <linux/kdev_t.h> | ||
16 | #include <linux/major.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/swap.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/vmalloc.h> | ||
21 | #include <linux/pagemap.h> | ||
22 | #include <linux/shm.h> | ||
23 | #include <linux/bootmem.h> | ||
24 | #include <linux/mount.h> | ||
25 | #include <linux/blkdev.h> | ||
26 | |||
27 | #include <asm/setup.h> | ||
28 | #include <asm/machdep.h> | ||
29 | #include <asm/page.h> | ||
30 | #include <asm/pgtable.h> | ||
31 | #include <asm/atarihw.h> | ||
32 | #include <asm/atari_stram.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/semaphore.h> | ||
35 | |||
36 | #include <linux/swapops.h> | ||
37 | |||
38 | #undef DEBUG | ||
39 | |||
40 | #ifdef DEBUG | ||
41 | #define DPRINTK(fmt,args...) printk( fmt, ##args ) | ||
42 | #else | ||
43 | #define DPRINTK(fmt,args...) | ||
44 | #endif | ||
45 | |||
46 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC) | ||
47 | /* abbrev for the && above... */ | ||
48 | #define DO_PROC | ||
49 | #include <linux/proc_fs.h> | ||
50 | #endif | ||
51 | |||
52 | /* Pre-swapping comments: | ||
53 | * | ||
54 | * ++roman: | ||
55 | * | ||
56 | * New version of ST-Ram buffer allocation. Instead of using the | ||
57 | * 1 MB - 4 KB that remain when the ST-Ram chunk starts at $1000 | ||
58 | * (1 MB granularity!), such buffers are reserved like this: | ||
59 | * | ||
60 | * - If the kernel resides in ST-Ram anyway, we can take the buffer | ||
61 | * from behind the current kernel data space the normal way | ||
62 | * (incrementing start_mem). | ||
63 | * | ||
64 | * - If the kernel is in TT-Ram, stram_init() initializes start and | ||
65 | * end of the available region. Buffers are allocated from there | ||
66 | * and mem_init() later marks the such used pages as reserved. | ||
67 | * Since each TT-Ram chunk is at least 4 MB in size, I hope there | ||
68 | * won't be an overrun of the ST-Ram region by normal kernel data | ||
69 | * space. | ||
70 | * | ||
71 | * For that, ST-Ram may only be allocated while kernel initialization | ||
72 | * is going on, or exactly: before mem_init() is called. There is also | ||
73 | * no provision now for freeing ST-Ram buffers. It seems that isn't | ||
74 | * really needed. | ||
75 | * | ||
76 | */ | ||
77 | |||
78 | /* | ||
79 | * New Nov 1997: Use ST-RAM as swap space! | ||
80 | * | ||
81 | * In the past, there were often problems with modules that require ST-RAM | ||
82 | * buffers. Such drivers have to use __get_dma_pages(), which unfortunately | ||
83 | * often isn't very successful in allocating more than 1 page :-( [1] The net | ||
84 | * result was that most of the time you couldn't insmod such modules (ataflop, | ||
85 | * ACSI, SCSI on Falcon, Atari internal framebuffer, not to speak of acsi_slm, | ||
86 | * which needs a 1 MB buffer... :-). | ||
87 | * | ||
88 | * To overcome this limitation, ST-RAM can now be turned into a very | ||
89 | * high-speed swap space. If a request for an ST-RAM buffer comes, the kernel | ||
90 | * now tries to unswap some pages on that swap device to make some free (and | ||
91 | * contiguous) space. This works much better in comparison to | ||
92 | * __get_dma_pages(), since used swap pages can be selectively freed by either | ||
93 | * moving them to somewhere else in swap space, or by reading them back into | ||
94 | * system memory. Ok, there operation of unswapping isn't really cheap (for | ||
95 | * each page, one has to go through the page tables of all processes), but it | ||
96 | * doesn't happen that often (only when allocation ST-RAM, i.e. when loading a | ||
97 | * module that needs ST-RAM). But it at least makes it possible to load such | ||
98 | * modules! | ||
99 | * | ||
100 | * It could also be that overall system performance increases a bit due to | ||
101 | * ST-RAM swapping, since slow ST-RAM isn't used anymore for holding data or | ||
102 | * executing code in. It's then just a (very fast, compared to disk) back | ||
103 | * storage for not-so-often needed data. (But this effect must be compared | ||
104 | * with the loss of total memory...) Don't know if the effect is already | ||
105 | * visible on a TT, where the speed difference between ST- and TT-RAM isn't | ||
106 | * that dramatic, but it should on machines where TT-RAM is really much faster | ||
107 | * (e.g. Afterburner). | ||
108 | * | ||
109 | * [1]: __get_free_pages() does a fine job if you only want one page, but if | ||
110 | * you want more (contiguous) pages, it can give you such a block only if | ||
111 | * there's already a free one. The algorithm can't try to free buffers or swap | ||
112 | * out something in order to make more free space, since all that page-freeing | ||
113 | * mechanisms work "target-less", i.e. they just free something, but not in a | ||
114 | * specific place. I.e., __get_free_pages() can't do anything to free | ||
115 | * *adjacent* pages :-( This situation becomes even worse for DMA memory, | ||
116 | * since the freeing algorithms are also blind to DMA capability of pages. | ||
117 | */ | ||
118 | |||
119 | /* 1998-10-20: ++andreas | ||
120 | unswap_by_move disabled because it does not handle swapped shm pages. | ||
121 | */ | ||
122 | |||
123 | /* 2000-05-01: ++andreas | ||
124 | Integrated with bootmem. Remove all traces of unswap_by_move. | ||
125 | */ | ||
126 | |||
127 | #ifdef CONFIG_STRAM_SWAP | ||
128 | #define ALIGN_IF_SWAP(x) PAGE_ALIGN(x) | ||
129 | #else | ||
130 | #define ALIGN_IF_SWAP(x) (x) | ||
131 | #endif | ||
132 | |||
133 | /* get index of swap page at address 'addr' */ | ||
134 | #define SWAP_NR(addr) (((addr) - swap_start) >> PAGE_SHIFT) | ||
135 | |||
136 | /* get address of swap page #'nr' */ | ||
137 | #define SWAP_ADDR(nr) (swap_start + ((nr) << PAGE_SHIFT)) | ||
138 | |||
139 | /* get number of pages for 'n' bytes (already page-aligned) */ | ||
140 | #define N_PAGES(n) ((n) >> PAGE_SHIFT) | ||
141 | |||
142 | /* The following two numbers define the maximum fraction of ST-RAM in total | ||
143 | * memory, below that the kernel would automatically use ST-RAM as swap | ||
144 | * space. This decision can be overridden with stram_swap= */ | ||
145 | #define MAX_STRAM_FRACTION_NOM 1 | ||
146 | #define MAX_STRAM_FRACTION_DENOM 3 | ||
147 | |||
148 | /* Start and end (virtual) of ST-RAM */ | ||
149 | static void *stram_start, *stram_end; | ||
150 | |||
151 | /* set after memory_init() executed and allocations via start_mem aren't | ||
152 | * possible anymore */ | ||
153 | static int mem_init_done; | ||
154 | |||
155 | /* set if kernel is in ST-RAM */ | ||
156 | static int kernel_in_stram; | ||
157 | |||
158 | typedef struct stram_block { | ||
159 | struct stram_block *next; | ||
160 | void *start; | ||
161 | unsigned long size; | ||
162 | unsigned flags; | ||
163 | const char *owner; | ||
164 | } BLOCK; | ||
165 | |||
166 | /* values for flags field */ | ||
167 | #define BLOCK_FREE 0x01 /* free structure in the BLOCKs pool */ | ||
168 | #define BLOCK_KMALLOCED 0x02 /* structure allocated by kmalloc() */ | ||
169 | #define BLOCK_GFP 0x08 /* block allocated with __get_dma_pages() */ | ||
170 | #define BLOCK_INSWAP 0x10 /* block allocated in swap space */ | ||
171 | |||
172 | /* list of allocated blocks */ | ||
173 | static BLOCK *alloc_list; | ||
174 | |||
175 | /* We can't always use kmalloc() to allocate BLOCK structures, since | ||
176 | * stram_alloc() can be called rather early. So we need some pool of | ||
177 | * statically allocated structures. 20 of them is more than enough, so in most | ||
178 | * cases we never should need to call kmalloc(). */ | ||
179 | #define N_STATIC_BLOCKS 20 | ||
180 | static BLOCK static_blocks[N_STATIC_BLOCKS]; | ||
181 | |||
182 | #ifdef CONFIG_STRAM_SWAP | ||
183 | /* max. number of bytes to use for swapping | ||
184 | * 0 = no ST-RAM swapping | ||
185 | * -1 = do swapping (to whole ST-RAM) if it's less than MAX_STRAM_FRACTION of | ||
186 | * total memory | ||
187 | */ | ||
188 | static int max_swap_size = -1; | ||
189 | |||
190 | /* start and end of swapping area */ | ||
191 | static void *swap_start, *swap_end; | ||
192 | |||
193 | /* The ST-RAM's swap info structure */ | ||
194 | static struct swap_info_struct *stram_swap_info; | ||
195 | |||
196 | /* The ST-RAM's swap type */ | ||
197 | static int stram_swap_type; | ||
198 | |||
199 | /* Semaphore for get_stram_region. */ | ||
200 | static DECLARE_MUTEX(stram_swap_sem); | ||
201 | |||
202 | /* major and minor device number of the ST-RAM device; for the major, we use | ||
203 | * the same as Amiga z2ram, which is really similar and impossible on Atari, | ||
204 | * and for the minor a relatively odd number to avoid the user creating and | ||
205 | * using that device. */ | ||
206 | #define STRAM_MAJOR Z2RAM_MAJOR | ||
207 | #define STRAM_MINOR 13 | ||
208 | |||
209 | /* Some impossible pointer value */ | ||
210 | #define MAGIC_FILE_P (struct file *)0xffffdead | ||
211 | |||
212 | #ifdef DO_PROC | ||
213 | static unsigned stat_swap_read; | ||
214 | static unsigned stat_swap_write; | ||
215 | static unsigned stat_swap_force; | ||
216 | #endif /* DO_PROC */ | ||
217 | |||
218 | #endif /* CONFIG_STRAM_SWAP */ | ||
219 | |||
220 | /***************************** Prototypes *****************************/ | ||
221 | |||
222 | #ifdef CONFIG_STRAM_SWAP | ||
223 | static int swap_init(void *start_mem, void *swap_data); | ||
224 | static void *get_stram_region( unsigned long n_pages ); | ||
225 | static void free_stram_region( unsigned long offset, unsigned long n_pages | ||
226 | ); | ||
227 | static int in_some_region(void *addr); | ||
228 | static unsigned long find_free_region( unsigned long n_pages, unsigned long | ||
229 | *total_free, unsigned long | ||
230 | *region_free ); | ||
231 | static void do_stram_request(request_queue_t *); | ||
232 | static int stram_open( struct inode *inode, struct file *filp ); | ||
233 | static int stram_release( struct inode *inode, struct file *filp ); | ||
234 | static void reserve_region(void *start, void *end); | ||
235 | #endif | ||
236 | static BLOCK *add_region( void *addr, unsigned long size ); | ||
237 | static BLOCK *find_region( void *addr ); | ||
238 | static int remove_region( BLOCK *block ); | ||
239 | |||
240 | /************************* End of Prototypes **************************/ | ||
241 | |||
242 | |||
243 | /* ------------------------------------------------------------------------ */ | ||
244 | /* Public Interface */ | ||
245 | /* ------------------------------------------------------------------------ */ | ||
246 | |||
247 | /* | ||
248 | * This init function is called very early by atari/config.c | ||
249 | * It initializes some internal variables needed for stram_alloc() | ||
250 | */ | ||
251 | void __init atari_stram_init(void) | ||
252 | { | ||
253 | int i; | ||
254 | |||
255 | /* initialize static blocks */ | ||
256 | for( i = 0; i < N_STATIC_BLOCKS; ++i ) | ||
257 | static_blocks[i].flags = BLOCK_FREE; | ||
258 | |||
259 | /* determine whether kernel code resides in ST-RAM (then ST-RAM is the | ||
260 | * first memory block at virtual 0x0) */ | ||
261 | stram_start = phys_to_virt(0); | ||
262 | kernel_in_stram = (stram_start == 0); | ||
263 | |||
264 | for( i = 0; i < m68k_num_memory; ++i ) { | ||
265 | if (m68k_memory[i].addr == 0) { | ||
266 | /* skip first 2kB or page (supervisor-only!) */ | ||
267 | stram_end = stram_start + m68k_memory[i].size; | ||
268 | return; | ||
269 | } | ||
270 | } | ||
271 | /* Should never come here! (There is always ST-Ram!) */ | ||
272 | panic( "atari_stram_init: no ST-RAM found!" ); | ||
273 | } | ||
274 | |||
275 | |||
276 | /* | ||
277 | * This function is called from setup_arch() to reserve the pages needed for | ||
278 | * ST-RAM management. | ||
279 | */ | ||
280 | void __init atari_stram_reserve_pages(void *start_mem) | ||
281 | { | ||
282 | #ifdef CONFIG_STRAM_SWAP | ||
283 | /* if max_swap_size is negative (i.e. no stram_swap= option given), | ||
284 | * determine at run time whether to use ST-RAM swapping */ | ||
285 | if (max_swap_size < 0) | ||
286 | /* Use swapping if ST-RAM doesn't make up more than MAX_STRAM_FRACTION | ||
287 | * of total memory. In that case, the max. size is set to 16 MB, | ||
288 | * because ST-RAM can never be bigger than that. | ||
289 | * Also, never use swapping on a Hades, there's no separate ST-RAM in | ||
290 | * that machine. */ | ||
291 | max_swap_size = | ||
292 | (!MACH_IS_HADES && | ||
293 | (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <= | ||
294 | ((unsigned long)high_memory>>PAGE_SHIFT)*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0; | ||
295 | DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size ); | ||
296 | #endif | ||
297 | |||
298 | /* always reserve first page of ST-RAM, the first 2 kB are | ||
299 | * supervisor-only! */ | ||
300 | if (!kernel_in_stram) | ||
301 | reserve_bootmem (0, PAGE_SIZE); | ||
302 | |||
303 | #ifdef CONFIG_STRAM_SWAP | ||
304 | { | ||
305 | void *swap_data; | ||
306 | |||
307 | start_mem = (void *) PAGE_ALIGN ((unsigned long) start_mem); | ||
308 | /* determine first page to use as swap: if the kernel is | ||
309 | in TT-RAM, this is the first page of (usable) ST-RAM; | ||
310 | otherwise just use the end of kernel data (= start_mem) */ | ||
311 | swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE : start_mem; | ||
312 | /* decrement by one page, rest of kernel assumes that first swap page | ||
313 | * is always reserved and maybe doesn't handle swp_entry == 0 | ||
314 | * correctly */ | ||
315 | swap_start -= PAGE_SIZE; | ||
316 | swap_end = stram_end; | ||
317 | if (swap_end-swap_start > max_swap_size) | ||
318 | swap_end = swap_start + max_swap_size; | ||
319 | DPRINTK( "atari_stram_reserve_pages: swapping enabled; " | ||
320 | "swap=%p-%p\n", swap_start, swap_end); | ||
321 | |||
322 | /* reserve some amount of memory for maintainance of | ||
323 | * swapping itself: one page for each 2048 (PAGE_SIZE/2) | ||
324 | * swap pages. (2 bytes for each page) */ | ||
325 | swap_data = start_mem; | ||
326 | start_mem += ((SWAP_NR(swap_end) + PAGE_SIZE/2 - 1) | ||
327 | >> (PAGE_SHIFT-1)) << PAGE_SHIFT; | ||
328 | /* correct swap_start if necessary */ | ||
329 | if (swap_start + PAGE_SIZE == swap_data) | ||
330 | swap_start = start_mem - PAGE_SIZE; | ||
331 | |||
332 | if (!swap_init( start_mem, swap_data )) { | ||
333 | printk( KERN_ERR "ST-RAM swap space initialization failed\n" ); | ||
334 | max_swap_size = 0; | ||
335 | return; | ||
336 | } | ||
337 | /* reserve region for swapping meta-data */ | ||
338 | reserve_region(swap_data, start_mem); | ||
339 | /* reserve swapping area itself */ | ||
340 | reserve_region(swap_start + PAGE_SIZE, swap_end); | ||
341 | |||
342 | /* | ||
343 | * If the whole ST-RAM is used for swapping, there are no allocatable | ||
344 | * dma pages left. But unfortunately, some shared parts of the kernel | ||
345 | * (particularly the SCSI mid-level) call __get_dma_pages() | ||
346 | * unconditionally :-( These calls then fail, and scsi.c even doesn't | ||
347 | * check for NULL return values and just crashes. The quick fix for | ||
348 | * this (instead of doing much clean up work in the SCSI code) is to | ||
349 | * pretend all pages are DMA-able by setting mach_max_dma_address to | ||
350 | * ULONG_MAX. This doesn't change any functionality so far, since | ||
351 | * get_dma_pages() shouldn't be used on Atari anyway anymore (better | ||
352 | * use atari_stram_alloc()), and the Atari SCSI drivers don't need DMA | ||
353 | * memory. But unfortunately there's now no kind of warning (even not | ||
354 | * a NULL return value) if you use get_dma_pages() nevertheless :-( | ||
355 | * You just will get non-DMA-able memory... | ||
356 | */ | ||
357 | mach_max_dma_address = 0xffffffff; | ||
358 | } | ||
359 | #endif | ||
360 | } | ||
361 | |||
362 | void atari_stram_mem_init_hook (void) | ||
363 | { | ||
364 | mem_init_done = 1; | ||
365 | } | ||
366 | |||
367 | |||
368 | /* | ||
369 | * This is main public interface: somehow allocate a ST-RAM block | ||
370 | * There are three strategies: | ||
371 | * | ||
372 | * - If we're before mem_init(), we have to make a static allocation. The | ||
373 | * region is taken in the kernel data area (if the kernel is in ST-RAM) or | ||
374 | * from the start of ST-RAM (if the kernel is in TT-RAM) and added to the | ||
375 | * rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel | ||
376 | * address space in the latter case. | ||
377 | * | ||
378 | * - If mem_init() already has been called and ST-RAM swapping is enabled, | ||
379 | * try to get the memory from the (pseudo) swap-space, either free already | ||
380 | * or by moving some other pages out of the swap. | ||
381 | * | ||
382 | * - If mem_init() already has been called, and ST-RAM swapping is not | ||
383 | * enabled, the only possibility is to try with __get_dma_pages(). This has | ||
384 | * the disadvantage that it's very hard to get more than 1 page, and it is | ||
385 | * likely to fail :-( | ||
386 | * | ||
387 | */ | ||
388 | void *atari_stram_alloc(long size, const char *owner) | ||
389 | { | ||
390 | void *addr = NULL; | ||
391 | BLOCK *block; | ||
392 | int flags; | ||
393 | |||
394 | DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner); | ||
395 | |||
396 | size = ALIGN_IF_SWAP(size); | ||
397 | DPRINTK( "atari_stram_alloc: rounded size = %08lx\n", size ); | ||
398 | #ifdef CONFIG_STRAM_SWAP | ||
399 | if (max_swap_size) { | ||
400 | /* If swapping is active: make some free space in the swap | ||
401 | "device". */ | ||
402 | DPRINTK( "atari_stram_alloc: after mem_init, swapping ok, " | ||
403 | "calling get_region\n" ); | ||
404 | addr = get_stram_region( N_PAGES(size) ); | ||
405 | flags = BLOCK_INSWAP; | ||
406 | } | ||
407 | else | ||
408 | #endif | ||
409 | if (!mem_init_done) | ||
410 | return alloc_bootmem_low(size); | ||
411 | else { | ||
412 | /* After mem_init() and no swapping: can only resort to | ||
413 | * __get_dma_pages() */ | ||
414 | addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size)); | ||
415 | flags = BLOCK_GFP; | ||
416 | DPRINTK( "atari_stram_alloc: after mem_init, swapping off, " | ||
417 | "get_pages=%p\n", addr ); | ||
418 | } | ||
419 | |||
420 | if (addr) { | ||
421 | if (!(block = add_region( addr, size ))) { | ||
422 | /* out of memory for BLOCK structure :-( */ | ||
423 | DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- " | ||
424 | "freeing again\n" ); | ||
425 | #ifdef CONFIG_STRAM_SWAP | ||
426 | if (flags == BLOCK_INSWAP) | ||
427 | free_stram_region( SWAP_NR(addr), N_PAGES(size) ); | ||
428 | else | ||
429 | #endif | ||
430 | free_pages((unsigned long)addr, get_order(size)); | ||
431 | return( NULL ); | ||
432 | } | ||
433 | block->owner = owner; | ||
434 | block->flags |= flags; | ||
435 | } | ||
436 | return( addr ); | ||
437 | } | ||
438 | |||
439 | void atari_stram_free( void *addr ) | ||
440 | |||
441 | { | ||
442 | BLOCK *block; | ||
443 | |||
444 | DPRINTK( "atari_stram_free(addr=%p)\n", addr ); | ||
445 | |||
446 | if (!(block = find_region( addr ))) { | ||
447 | printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p " | ||
448 | "from %p\n", addr, __builtin_return_address(0) ); | ||
449 | return; | ||
450 | } | ||
451 | DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, " | ||
452 | "flags=%02x\n", block, block->size, block->owner, block->flags ); | ||
453 | |||
454 | #ifdef CONFIG_STRAM_SWAP | ||
455 | if (!max_swap_size) { | ||
456 | #endif | ||
457 | if (block->flags & BLOCK_GFP) { | ||
458 | DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n", | ||
459 | get_order(block->size)); | ||
460 | free_pages((unsigned long)addr, get_order(block->size)); | ||
461 | } | ||
462 | else | ||
463 | goto fail; | ||
464 | #ifdef CONFIG_STRAM_SWAP | ||
465 | } | ||
466 | else if (block->flags & BLOCK_INSWAP) { | ||
467 | DPRINTK( "atari_stram_free: is swap-alloced\n" ); | ||
468 | free_stram_region( SWAP_NR(block->start), N_PAGES(block->size) ); | ||
469 | } | ||
470 | else | ||
471 | goto fail; | ||
472 | #endif | ||
473 | remove_region( block ); | ||
474 | return; | ||
475 | |||
476 | fail: | ||
477 | printk( KERN_ERR "atari_stram_free: cannot free block at %p " | ||
478 | "(called from %p)\n", addr, __builtin_return_address(0) ); | ||
479 | } | ||
480 | |||
481 | |||
482 | #ifdef CONFIG_STRAM_SWAP | ||
483 | |||
484 | |||
485 | /* ------------------------------------------------------------------------ */ | ||
486 | /* Main Swapping Functions */ | ||
487 | /* ------------------------------------------------------------------------ */ | ||
488 | |||
489 | |||
490 | /* | ||
491 | * Initialize ST-RAM swap device | ||
492 | * (lots copied and modified from sys_swapon() in mm/swapfile.c) | ||
493 | */ | ||
494 | static int __init swap_init(void *start_mem, void *swap_data) | ||
495 | { | ||
496 | static struct dentry fake_dentry; | ||
497 | static struct vfsmount fake_vfsmnt; | ||
498 | struct swap_info_struct *p; | ||
499 | struct inode swap_inode; | ||
500 | unsigned int type; | ||
501 | void *addr; | ||
502 | int i, j, k, prev; | ||
503 | |||
504 | DPRINTK("swap_init(start_mem=%p, swap_data=%p)\n", | ||
505 | start_mem, swap_data); | ||
506 | |||
507 | /* need at least one page for swapping to (and this also isn't very | ||
508 | * much... :-) */ | ||
509 | if (swap_end - swap_start < 2*PAGE_SIZE) { | ||
510 | printk( KERN_WARNING "stram_swap_init: swap space too small\n" ); | ||
511 | return( 0 ); | ||
512 | } | ||
513 | |||
514 | /* find free slot in swap_info */ | ||
515 | for( p = swap_info, type = 0; type < nr_swapfiles; type++, p++ ) | ||
516 | if (!(p->flags & SWP_USED)) | ||
517 | break; | ||
518 | if (type >= MAX_SWAPFILES) { | ||
519 | printk( KERN_WARNING "stram_swap_init: max. number of " | ||
520 | "swap devices exhausted\n" ); | ||
521 | return( 0 ); | ||
522 | } | ||
523 | if (type >= nr_swapfiles) | ||
524 | nr_swapfiles = type+1; | ||
525 | |||
526 | stram_swap_info = p; | ||
527 | stram_swap_type = type; | ||
528 | |||
529 | /* fake some dir cache entries to give us some name in /dev/swaps */ | ||
530 | fake_dentry.d_parent = &fake_dentry; | ||
531 | fake_dentry.d_name.name = "stram (internal)"; | ||
532 | fake_dentry.d_name.len = 16; | ||
533 | fake_vfsmnt.mnt_parent = &fake_vfsmnt; | ||
534 | |||
535 | p->flags = SWP_USED; | ||
536 | p->swap_file = &fake_dentry; | ||
537 | p->swap_vfsmnt = &fake_vfsmnt; | ||
538 | p->swap_map = swap_data; | ||
539 | p->cluster_nr = 0; | ||
540 | p->next = -1; | ||
541 | p->prio = 0x7ff0; /* a rather high priority, but not the higest | ||
542 | * to give the user a chance to override */ | ||
543 | |||
544 | /* call stram_open() directly, avoids at least the overhead in | ||
545 | * constructing a dummy file structure... */ | ||
546 | swap_inode.i_rdev = MKDEV( STRAM_MAJOR, STRAM_MINOR ); | ||
547 | stram_open( &swap_inode, MAGIC_FILE_P ); | ||
548 | p->max = SWAP_NR(swap_end); | ||
549 | |||
550 | /* initialize swap_map: set regions that are already allocated or belong | ||
551 | * to kernel data space to SWAP_MAP_BAD, otherwise to free */ | ||
552 | j = 0; /* # of free pages */ | ||
553 | k = 0; /* # of already allocated pages (from pre-mem_init stram_alloc()) */ | ||
554 | p->lowest_bit = 0; | ||
555 | p->highest_bit = 0; | ||
556 | for( i = 1, addr = SWAP_ADDR(1); i < p->max; | ||
557 | i++, addr += PAGE_SIZE ) { | ||
558 | if (in_some_region( addr )) { | ||
559 | p->swap_map[i] = SWAP_MAP_BAD; | ||
560 | ++k; | ||
561 | } | ||
562 | else if (kernel_in_stram && addr < start_mem ) { | ||
563 | p->swap_map[i] = SWAP_MAP_BAD; | ||
564 | } | ||
565 | else { | ||
566 | p->swap_map[i] = 0; | ||
567 | ++j; | ||
568 | if (!p->lowest_bit) p->lowest_bit = i; | ||
569 | p->highest_bit = i; | ||
570 | } | ||
571 | } | ||
572 | /* first page always reserved (and doesn't really belong to swap space) */ | ||
573 | p->swap_map[0] = SWAP_MAP_BAD; | ||
574 | |||
575 | /* now swapping to this device ok */ | ||
576 | p->pages = j + k; | ||
577 | swap_list_lock(); | ||
578 | nr_swap_pages += j; | ||
579 | p->flags = SWP_WRITEOK; | ||
580 | |||
581 | /* insert swap space into swap_list */ | ||
582 | prev = -1; | ||
583 | for (i = swap_list.head; i >= 0; i = swap_info[i].next) { | ||
584 | if (p->prio >= swap_info[i].prio) { | ||
585 | break; | ||
586 | } | ||
587 | prev = i; | ||
588 | } | ||
589 | p->next = i; | ||
590 | if (prev < 0) { | ||
591 | swap_list.head = swap_list.next = p - swap_info; | ||
592 | } else { | ||
593 | swap_info[prev].next = p - swap_info; | ||
594 | } | ||
595 | swap_list_unlock(); | ||
596 | |||
597 | printk( KERN_INFO "Using %dk (%d pages) of ST-RAM as swap space.\n", | ||
598 | p->pages << 2, p->pages ); | ||
599 | return( 1 ); | ||
600 | } | ||
601 | |||
602 | |||
603 | /* | ||
604 | * The swap entry has been read in advance, and we return 1 to indicate | ||
605 | * that the page has been used or is no longer needed. | ||
606 | * | ||
607 | * Always set the resulting pte to be nowrite (the same as COW pages | ||
608 | * after one process has exited). We don't know just how many PTEs will | ||
609 | * share this swap entry, so be cautious and let do_wp_page work out | ||
610 | * what to do if a write is requested later. | ||
611 | */ | ||
612 | static inline void unswap_pte(struct vm_area_struct * vma, unsigned long | ||
613 | address, pte_t *dir, swp_entry_t entry, | ||
614 | struct page *page) | ||
615 | { | ||
616 | pte_t pte = *dir; | ||
617 | |||
618 | if (pte_none(pte)) | ||
619 | return; | ||
620 | if (pte_present(pte)) { | ||
621 | /* If this entry is swap-cached, then page must already | ||
622 | hold the right address for any copies in physical | ||
623 | memory */ | ||
624 | if (pte_page(pte) != page) | ||
625 | return; | ||
626 | /* We will be removing the swap cache in a moment, so... */ | ||
627 | set_pte(dir, pte_mkdirty(pte)); | ||
628 | return; | ||
629 | } | ||
630 | if (pte_val(pte) != entry.val) | ||
631 | return; | ||
632 | |||
633 | DPRINTK("unswap_pte: replacing entry %08lx by new page %p", | ||
634 | entry.val, page); | ||
635 | set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); | ||
636 | swap_free(entry); | ||
637 | get_page(page); | ||
638 | inc_mm_counter(vma->vm_mm, rss); | ||
639 | } | ||
640 | |||
641 | static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir, | ||
642 | unsigned long address, unsigned long size, | ||
643 | unsigned long offset, swp_entry_t entry, | ||
644 | struct page *page) | ||
645 | { | ||
646 | pte_t * pte; | ||
647 | unsigned long end; | ||
648 | |||
649 | if (pmd_none(*dir)) | ||
650 | return; | ||
651 | if (pmd_bad(*dir)) { | ||
652 | pmd_ERROR(*dir); | ||
653 | pmd_clear(dir); | ||
654 | return; | ||
655 | } | ||
656 | pte = pte_offset_kernel(dir, address); | ||
657 | offset += address & PMD_MASK; | ||
658 | address &= ~PMD_MASK; | ||
659 | end = address + size; | ||
660 | if (end > PMD_SIZE) | ||
661 | end = PMD_SIZE; | ||
662 | do { | ||
663 | unswap_pte(vma, offset+address-vma->vm_start, pte, entry, page); | ||
664 | address += PAGE_SIZE; | ||
665 | pte++; | ||
666 | } while (address < end); | ||
667 | } | ||
668 | |||
669 | static inline void unswap_pgd(struct vm_area_struct * vma, pgd_t *dir, | ||
670 | unsigned long address, unsigned long size, | ||
671 | swp_entry_t entry, struct page *page) | ||
672 | { | ||
673 | pmd_t * pmd; | ||
674 | unsigned long offset, end; | ||
675 | |||
676 | if (pgd_none(*dir)) | ||
677 | return; | ||
678 | if (pgd_bad(*dir)) { | ||
679 | pgd_ERROR(*dir); | ||
680 | pgd_clear(dir); | ||
681 | return; | ||
682 | } | ||
683 | pmd = pmd_offset(dir, address); | ||
684 | offset = address & PGDIR_MASK; | ||
685 | address &= ~PGDIR_MASK; | ||
686 | end = address + size; | ||
687 | if (end > PGDIR_SIZE) | ||
688 | end = PGDIR_SIZE; | ||
689 | do { | ||
690 | unswap_pmd(vma, pmd, address, end - address, offset, entry, | ||
691 | page); | ||
692 | address = (address + PMD_SIZE) & PMD_MASK; | ||
693 | pmd++; | ||
694 | } while (address < end); | ||
695 | } | ||
696 | |||
697 | static void unswap_vma(struct vm_area_struct * vma, pgd_t *pgdir, | ||
698 | swp_entry_t entry, struct page *page) | ||
699 | { | ||
700 | unsigned long start = vma->vm_start, end = vma->vm_end; | ||
701 | |||
702 | do { | ||
703 | unswap_pgd(vma, pgdir, start, end - start, entry, page); | ||
704 | start = (start + PGDIR_SIZE) & PGDIR_MASK; | ||
705 | pgdir++; | ||
706 | } while (start < end); | ||
707 | } | ||
708 | |||
709 | static void unswap_process(struct mm_struct * mm, swp_entry_t entry, | ||
710 | struct page *page) | ||
711 | { | ||
712 | struct vm_area_struct* vma; | ||
713 | |||
714 | /* | ||
715 | * Go through process' page directory. | ||
716 | */ | ||
717 | if (!mm) | ||
718 | return; | ||
719 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
720 | pgd_t * pgd = pgd_offset(mm, vma->vm_start); | ||
721 | unswap_vma(vma, pgd, entry, page); | ||
722 | } | ||
723 | } | ||
724 | |||
725 | |||
726 | static int unswap_by_read(unsigned short *map, unsigned long max, | ||
727 | unsigned long start, unsigned long n_pages) | ||
728 | { | ||
729 | struct task_struct *p; | ||
730 | struct page *page; | ||
731 | swp_entry_t entry; | ||
732 | unsigned long i; | ||
733 | |||
734 | DPRINTK( "unswapping %lu..%lu by reading in\n", | ||
735 | start, start+n_pages-1 ); | ||
736 | |||
737 | for( i = start; i < start+n_pages; ++i ) { | ||
738 | if (map[i] == SWAP_MAP_BAD) { | ||
739 | printk( KERN_ERR "get_stram_region: page %lu already " | ||
740 | "reserved??\n", i ); | ||
741 | continue; | ||
742 | } | ||
743 | |||
744 | if (map[i]) { | ||
745 | entry = swp_entry(stram_swap_type, i); | ||
746 | DPRINTK("unswap: map[i=%lu]=%u nr_swap=%ld\n", | ||
747 | i, map[i], nr_swap_pages); | ||
748 | |||
749 | swap_device_lock(stram_swap_info); | ||
750 | map[i]++; | ||
751 | swap_device_unlock(stram_swap_info); | ||
752 | /* Get a page for the entry, using the existing | ||
753 | swap cache page if there is one. Otherwise, | ||
754 | get a clean page and read the swap into it. */ | ||
755 | page = read_swap_cache_async(entry, NULL, 0); | ||
756 | if (!page) { | ||
757 | swap_free(entry); | ||
758 | return -ENOMEM; | ||
759 | } | ||
760 | read_lock(&tasklist_lock); | ||
761 | for_each_process(p) | ||
762 | unswap_process(p->mm, entry, page); | ||
763 | read_unlock(&tasklist_lock); | ||
764 | shmem_unuse(entry, page); | ||
765 | /* Now get rid of the extra reference to the | ||
766 | temporary page we've been using. */ | ||
767 | if (PageSwapCache(page)) | ||
768 | delete_from_swap_cache(page); | ||
769 | __free_page(page); | ||
770 | #ifdef DO_PROC | ||
771 | stat_swap_force++; | ||
772 | #endif | ||
773 | } | ||
774 | |||
775 | DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%ld\n", | ||
776 | i, map[i], nr_swap_pages ); | ||
777 | swap_list_lock(); | ||
778 | swap_device_lock(stram_swap_info); | ||
779 | map[i] = SWAP_MAP_BAD; | ||
780 | if (stram_swap_info->lowest_bit == i) | ||
781 | stram_swap_info->lowest_bit++; | ||
782 | if (stram_swap_info->highest_bit == i) | ||
783 | stram_swap_info->highest_bit--; | ||
784 | --nr_swap_pages; | ||
785 | swap_device_unlock(stram_swap_info); | ||
786 | swap_list_unlock(); | ||
787 | } | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | /* | ||
793 | * reserve a region in ST-RAM swap space for an allocation | ||
794 | */ | ||
795 | static void *get_stram_region( unsigned long n_pages ) | ||
796 | { | ||
797 | unsigned short *map = stram_swap_info->swap_map; | ||
798 | unsigned long max = stram_swap_info->max; | ||
799 | unsigned long start, total_free, region_free; | ||
800 | int err; | ||
801 | void *ret = NULL; | ||
802 | |||
803 | DPRINTK( "get_stram_region(n_pages=%lu)\n", n_pages ); | ||
804 | |||
805 | down(&stram_swap_sem); | ||
806 | |||
807 | /* disallow writing to the swap device now */ | ||
808 | stram_swap_info->flags = SWP_USED; | ||
809 | |||
810 | /* find a region of n_pages pages in the swap space including as much free | ||
811 | * pages as possible (and excluding any already-reserved pages). */ | ||
812 | if (!(start = find_free_region( n_pages, &total_free, ®ion_free ))) | ||
813 | goto end; | ||
814 | DPRINTK( "get_stram_region: region starts at %lu, has %lu free pages\n", | ||
815 | start, region_free ); | ||
816 | |||
817 | err = unswap_by_read(map, max, start, n_pages); | ||
818 | if (err) | ||
819 | goto end; | ||
820 | |||
821 | ret = SWAP_ADDR(start); | ||
822 | end: | ||
823 | /* allow using swap device again */ | ||
824 | stram_swap_info->flags = SWP_WRITEOK; | ||
825 | up(&stram_swap_sem); | ||
826 | DPRINTK( "get_stram_region: returning %p\n", ret ); | ||
827 | return( ret ); | ||
828 | } | ||
829 | |||
830 | |||
831 | /* | ||
832 | * free a reserved region in ST-RAM swap space | ||
833 | */ | ||
834 | static void free_stram_region( unsigned long offset, unsigned long n_pages ) | ||
835 | { | ||
836 | unsigned short *map = stram_swap_info->swap_map; | ||
837 | |||
838 | DPRINTK( "free_stram_region(offset=%lu,n_pages=%lu)\n", offset, n_pages ); | ||
839 | |||
840 | if (offset < 1 || offset + n_pages > stram_swap_info->max) { | ||
841 | printk( KERN_ERR "free_stram_region: Trying to free non-ST-RAM\n" ); | ||
842 | return; | ||
843 | } | ||
844 | |||
845 | swap_list_lock(); | ||
846 | swap_device_lock(stram_swap_info); | ||
847 | /* un-reserve the freed pages */ | ||
848 | for( ; n_pages > 0; ++offset, --n_pages ) { | ||
849 | if (map[offset] != SWAP_MAP_BAD) | ||
850 | printk( KERN_ERR "free_stram_region: Swap page %lu was not " | ||
851 | "reserved\n", offset ); | ||
852 | map[offset] = 0; | ||
853 | } | ||
854 | |||
855 | /* update swapping meta-data */ | ||
856 | if (offset < stram_swap_info->lowest_bit) | ||
857 | stram_swap_info->lowest_bit = offset; | ||
858 | if (offset+n_pages-1 > stram_swap_info->highest_bit) | ||
859 | stram_swap_info->highest_bit = offset+n_pages-1; | ||
860 | if (stram_swap_info->prio > swap_info[swap_list.next].prio) | ||
861 | swap_list.next = swap_list.head; | ||
862 | nr_swap_pages += n_pages; | ||
863 | swap_device_unlock(stram_swap_info); | ||
864 | swap_list_unlock(); | ||
865 | } | ||
866 | |||
867 | |||
868 | /* ------------------------------------------------------------------------ */ | ||
869 | /* Utility Functions for Swapping */ | ||
870 | /* ------------------------------------------------------------------------ */ | ||
871 | |||
872 | |||
873 | /* is addr in some of the allocated regions? */ | ||
874 | static int in_some_region(void *addr) | ||
875 | { | ||
876 | BLOCK *p; | ||
877 | |||
878 | for( p = alloc_list; p; p = p->next ) { | ||
879 | if (p->start <= addr && addr < p->start + p->size) | ||
880 | return( 1 ); | ||
881 | } | ||
882 | return( 0 ); | ||
883 | } | ||
884 | |||
885 | |||
886 | static unsigned long find_free_region(unsigned long n_pages, | ||
887 | unsigned long *total_free, | ||
888 | unsigned long *region_free) | ||
889 | { | ||
890 | unsigned short *map = stram_swap_info->swap_map; | ||
891 | unsigned long max = stram_swap_info->max; | ||
892 | unsigned long head, tail, max_start; | ||
893 | long nfree, max_free; | ||
894 | |||
895 | /* first scan the swap space for a suitable place for the allocation */ | ||
896 | head = 1; | ||
897 | max_start = 0; | ||
898 | max_free = -1; | ||
899 | *total_free = 0; | ||
900 | |||
901 | start_over: | ||
902 | /* increment tail until final window size reached, and count free pages */ | ||
903 | nfree = 0; | ||
904 | for( tail = head; tail-head < n_pages && tail < max; ++tail ) { | ||
905 | if (map[tail] == SWAP_MAP_BAD) { | ||
906 | head = tail+1; | ||
907 | goto start_over; | ||
908 | } | ||
909 | if (!map[tail]) { | ||
910 | ++nfree; | ||
911 | ++*total_free; | ||
912 | } | ||
913 | } | ||
914 | if (tail-head < n_pages) | ||
915 | goto out; | ||
916 | if (nfree > max_free) { | ||
917 | max_start = head; | ||
918 | max_free = nfree; | ||
919 | if (max_free >= n_pages) | ||
920 | /* don't need more free pages... :-) */ | ||
921 | goto out; | ||
922 | } | ||
923 | |||
924 | /* now shift the window and look for the area where as much pages as | ||
925 | * possible are free */ | ||
926 | while( tail < max ) { | ||
927 | nfree -= (map[head++] == 0); | ||
928 | if (map[tail] == SWAP_MAP_BAD) { | ||
929 | head = tail+1; | ||
930 | goto start_over; | ||
931 | } | ||
932 | if (!map[tail]) { | ||
933 | ++nfree; | ||
934 | ++*total_free; | ||
935 | } | ||
936 | ++tail; | ||
937 | if (nfree > max_free) { | ||
938 | max_start = head; | ||
939 | max_free = nfree; | ||
940 | if (max_free >= n_pages) | ||
941 | /* don't need more free pages... :-) */ | ||
942 | goto out; | ||
943 | } | ||
944 | } | ||
945 | |||
946 | out: | ||
947 | if (max_free < 0) { | ||
948 | printk( KERN_NOTICE "get_stram_region: ST-RAM too full or fragmented " | ||
949 | "-- can't allocate %lu pages\n", n_pages ); | ||
950 | return( 0 ); | ||
951 | } | ||
952 | |||
953 | *region_free = max_free; | ||
954 | return( max_start ); | ||
955 | } | ||
956 | |||
957 | |||
958 | /* setup parameters from command line */ | ||
959 | void __init stram_swap_setup(char *str, int *ints) | ||
960 | { | ||
961 | if (ints[0] >= 1) | ||
962 | max_swap_size = ((ints[1] < 0 ? 0 : ints[1]) * 1024) & PAGE_MASK; | ||
963 | } | ||
964 | |||
965 | |||
966 | /* ------------------------------------------------------------------------ */ | ||
967 | /* ST-RAM device */ | ||
968 | /* ------------------------------------------------------------------------ */ | ||
969 | |||
970 | static int refcnt; | ||
971 | |||
972 | static void do_stram_request(request_queue_t *q) | ||
973 | { | ||
974 | struct request *req; | ||
975 | |||
976 | while ((req = elv_next_request(q)) != NULL) { | ||
977 | void *start = swap_start + (req->sector << 9); | ||
978 | unsigned long len = req->current_nr_sectors << 9; | ||
979 | if ((start + len) > swap_end) { | ||
980 | printk( KERN_ERR "stram: bad access beyond end of device: " | ||
981 | "block=%ld, count=%d\n", | ||
982 | req->sector, | ||
983 | req->current_nr_sectors ); | ||
984 | end_request(req, 0); | ||
985 | continue; | ||
986 | } | ||
987 | |||
988 | if (req->cmd == READ) { | ||
989 | memcpy(req->buffer, start, len); | ||
990 | #ifdef DO_PROC | ||
991 | stat_swap_read += N_PAGES(len); | ||
992 | #endif | ||
993 | } | ||
994 | else { | ||
995 | memcpy(start, req->buffer, len); | ||
996 | #ifdef DO_PROC | ||
997 | stat_swap_write += N_PAGES(len); | ||
998 | #endif | ||
999 | } | ||
1000 | end_request(req, 1); | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | |||
1005 | static int stram_open( struct inode *inode, struct file *filp ) | ||
1006 | { | ||
1007 | if (filp != MAGIC_FILE_P) { | ||
1008 | printk( KERN_NOTICE "Only kernel can open ST-RAM device\n" ); | ||
1009 | return( -EPERM ); | ||
1010 | } | ||
1011 | if (refcnt) | ||
1012 | return( -EBUSY ); | ||
1013 | ++refcnt; | ||
1014 | return( 0 ); | ||
1015 | } | ||
1016 | |||
1017 | static int stram_release( struct inode *inode, struct file *filp ) | ||
1018 | { | ||
1019 | if (filp != MAGIC_FILE_P) { | ||
1020 | printk( KERN_NOTICE "Only kernel can close ST-RAM device\n" ); | ||
1021 | return( -EPERM ); | ||
1022 | } | ||
1023 | if (refcnt > 0) | ||
1024 | --refcnt; | ||
1025 | return( 0 ); | ||
1026 | } | ||
1027 | |||
1028 | |||
1029 | static struct block_device_operations stram_fops = { | ||
1030 | .open = stram_open, | ||
1031 | .release = stram_release, | ||
1032 | }; | ||
1033 | |||
1034 | static struct gendisk *stram_disk; | ||
1035 | static struct request_queue *stram_queue; | ||
1036 | static DEFINE_SPINLOCK(stram_lock); | ||
1037 | |||
1038 | int __init stram_device_init(void) | ||
1039 | { | ||
1040 | if (!MACH_IS_ATARI) | ||
1041 | /* no point in initializing this, I hope */ | ||
1042 | return -ENXIO; | ||
1043 | |||
1044 | if (!max_swap_size) | ||
1045 | /* swapping not enabled */ | ||
1046 | return -ENXIO; | ||
1047 | stram_disk = alloc_disk(1); | ||
1048 | if (!stram_disk) | ||
1049 | return -ENOMEM; | ||
1050 | |||
1051 | if (register_blkdev(STRAM_MAJOR, "stram")) { | ||
1052 | put_disk(stram_disk); | ||
1053 | return -ENXIO; | ||
1054 | } | ||
1055 | |||
1056 | stram_queue = blk_init_queue(do_stram_request, &stram_lock); | ||
1057 | if (!stram_queue) { | ||
1058 | unregister_blkdev(STRAM_MAJOR, "stram"); | ||
1059 | put_disk(stram_disk); | ||
1060 | return -ENOMEM; | ||
1061 | } | ||
1062 | |||
1063 | stram_disk->major = STRAM_MAJOR; | ||
1064 | stram_disk->first_minor = STRAM_MINOR; | ||
1065 | stram_disk->fops = &stram_fops; | ||
1066 | stram_disk->queue = stram_queue; | ||
1067 | sprintf(stram_disk->disk_name, "stram"); | ||
1068 | set_capacity(stram_disk, (swap_end - swap_start)/512); | ||
1069 | add_disk(stram_disk); | ||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | |||
1075 | /* ------------------------------------------------------------------------ */ | ||
1076 | /* Misc Utility Functions */ | ||
1077 | /* ------------------------------------------------------------------------ */ | ||
1078 | |||
1079 | /* reserve a range of pages */ | ||
1080 | static void reserve_region(void *start, void *end) | ||
1081 | { | ||
1082 | reserve_bootmem (virt_to_phys(start), end - start); | ||
1083 | } | ||
1084 | |||
1085 | #endif /* CONFIG_STRAM_SWAP */ | ||
1086 | |||
1087 | |||
1088 | /* ------------------------------------------------------------------------ */ | ||
1089 | /* Region Management */ | ||
1090 | /* ------------------------------------------------------------------------ */ | ||
1091 | |||
1092 | |||
1093 | /* insert a region into the alloced list (sorted) */ | ||
1094 | static BLOCK *add_region( void *addr, unsigned long size ) | ||
1095 | { | ||
1096 | BLOCK **p, *n = NULL; | ||
1097 | int i; | ||
1098 | |||
1099 | for( i = 0; i < N_STATIC_BLOCKS; ++i ) { | ||
1100 | if (static_blocks[i].flags & BLOCK_FREE) { | ||
1101 | n = &static_blocks[i]; | ||
1102 | n->flags = 0; | ||
1103 | break; | ||
1104 | } | ||
1105 | } | ||
1106 | if (!n && mem_init_done) { | ||
1107 | /* if statics block pool exhausted and we can call kmalloc() already | ||
1108 | * (after mem_init()), try that */ | ||
1109 | n = kmalloc( sizeof(BLOCK), GFP_KERNEL ); | ||
1110 | if (n) | ||
1111 | n->flags = BLOCK_KMALLOCED; | ||
1112 | } | ||
1113 | if (!n) { | ||
1114 | printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" ); | ||
1115 | return( NULL ); | ||
1116 | } | ||
1117 | n->start = addr; | ||
1118 | n->size = size; | ||
1119 | |||
1120 | for( p = &alloc_list; *p; p = &((*p)->next) ) | ||
1121 | if ((*p)->start > addr) break; | ||
1122 | n->next = *p; | ||
1123 | *p = n; | ||
1124 | |||
1125 | return( n ); | ||
1126 | } | ||
1127 | |||
1128 | |||
1129 | /* find a region (by start addr) in the alloced list */ | ||
1130 | static BLOCK *find_region( void *addr ) | ||
1131 | { | ||
1132 | BLOCK *p; | ||
1133 | |||
1134 | for( p = alloc_list; p; p = p->next ) { | ||
1135 | if (p->start == addr) | ||
1136 | return( p ); | ||
1137 | if (p->start > addr) | ||
1138 | break; | ||
1139 | } | ||
1140 | return( NULL ); | ||
1141 | } | ||
1142 | |||
1143 | |||
1144 | /* remove a block from the alloced list */ | ||
1145 | static int remove_region( BLOCK *block ) | ||
1146 | { | ||
1147 | BLOCK **p; | ||
1148 | |||
1149 | for( p = &alloc_list; *p; p = &((*p)->next) ) | ||
1150 | if (*p == block) break; | ||
1151 | if (!*p) | ||
1152 | return( 0 ); | ||
1153 | |||
1154 | *p = block->next; | ||
1155 | if (block->flags & BLOCK_KMALLOCED) | ||
1156 | kfree( block ); | ||
1157 | else | ||
1158 | block->flags |= BLOCK_FREE; | ||
1159 | return( 1 ); | ||
1160 | } | ||
1161 | |||
1162 | |||
1163 | |||
1164 | /* ------------------------------------------------------------------------ */ | ||
1165 | /* /proc statistics file stuff */ | ||
1166 | /* ------------------------------------------------------------------------ */ | ||
1167 | |||
1168 | #ifdef DO_PROC | ||
1169 | |||
1170 | #define PRINT_PROC(fmt,args...) len += sprintf( buf+len, fmt, ##args ) | ||
1171 | |||
1172 | int get_stram_list( char *buf ) | ||
1173 | { | ||
1174 | int len = 0; | ||
1175 | BLOCK *p; | ||
1176 | #ifdef CONFIG_STRAM_SWAP | ||
1177 | int i; | ||
1178 | unsigned short *map = stram_swap_info->swap_map; | ||
1179 | unsigned long max = stram_swap_info->max; | ||
1180 | unsigned free = 0, used = 0, rsvd = 0; | ||
1181 | #endif | ||
1182 | |||
1183 | #ifdef CONFIG_STRAM_SWAP | ||
1184 | if (max_swap_size) { | ||
1185 | for( i = 1; i < max; ++i ) { | ||
1186 | if (!map[i]) | ||
1187 | ++free; | ||
1188 | else if (map[i] == SWAP_MAP_BAD) | ||
1189 | ++rsvd; | ||
1190 | else | ||
1191 | ++used; | ||
1192 | } | ||
1193 | PRINT_PROC( | ||
1194 | "Total ST-RAM: %8u kB\n" | ||
1195 | "Total ST-RAM swap: %8lu kB\n" | ||
1196 | "Free swap: %8u kB\n" | ||
1197 | "Used swap: %8u kB\n" | ||
1198 | "Allocated swap: %8u kB\n" | ||
1199 | "Swap Reads: %8u\n" | ||
1200 | "Swap Writes: %8u\n" | ||
1201 | "Swap Forced Reads: %8u\n", | ||
1202 | (stram_end - stram_start) >> 10, | ||
1203 | (max-1) << (PAGE_SHIFT-10), | ||
1204 | free << (PAGE_SHIFT-10), | ||
1205 | used << (PAGE_SHIFT-10), | ||
1206 | rsvd << (PAGE_SHIFT-10), | ||
1207 | stat_swap_read, | ||
1208 | stat_swap_write, | ||
1209 | stat_swap_force ); | ||
1210 | } | ||
1211 | else { | ||
1212 | #endif | ||
1213 | PRINT_PROC( "ST-RAM swapping disabled\n" ); | ||
1214 | PRINT_PROC("Total ST-RAM: %8u kB\n", | ||
1215 | (stram_end - stram_start) >> 10); | ||
1216 | #ifdef CONFIG_STRAM_SWAP | ||
1217 | } | ||
1218 | #endif | ||
1219 | |||
1220 | PRINT_PROC( "Allocated regions:\n" ); | ||
1221 | for( p = alloc_list; p; p = p->next ) { | ||
1222 | if (len + 50 >= PAGE_SIZE) | ||
1223 | break; | ||
1224 | PRINT_PROC("0x%08lx-0x%08lx: %s (", | ||
1225 | virt_to_phys(p->start), | ||
1226 | virt_to_phys(p->start+p->size-1), | ||
1227 | p->owner); | ||
1228 | if (p->flags & BLOCK_GFP) | ||
1229 | PRINT_PROC( "page-alloced)\n" ); | ||
1230 | else if (p->flags & BLOCK_INSWAP) | ||
1231 | PRINT_PROC( "in swap)\n" ); | ||
1232 | else | ||
1233 | PRINT_PROC( "??)\n" ); | ||
1234 | } | ||
1235 | |||
1236 | return( len ); | ||
1237 | } | ||
1238 | |||
1239 | #endif | ||
1240 | |||
1241 | |||
1242 | /* | ||
1243 | * Local variables: | ||
1244 | * c-indent-level: 4 | ||
1245 | * tab-width: 4 | ||
1246 | * End: | ||
1247 | */ | ||
diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c new file mode 100644 index 000000000000..6df7fb60dfea --- /dev/null +++ b/arch/m68k/atari/time.c | |||
@@ -0,0 +1,348 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/atari/time.c | ||
3 | * | ||
4 | * Atari time and real time clock stuff | ||
5 | * | ||
6 | * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek | ||
7 | * | ||
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 | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/mc146818rtc.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/rtc.h> | ||
18 | #include <linux/bcd.h> | ||
19 | |||
20 | #include <asm/atariints.h> | ||
21 | |||
22 | void __init | ||
23 | atari_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) | ||
24 | { | ||
25 | /* set Timer C data Register */ | ||
26 | mfp.tim_dt_c = INT_TICKS; | ||
27 | /* start timer C, div = 1:100 */ | ||
28 | mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; | ||
29 | /* install interrupt service routine for MFP Timer C */ | ||
30 | request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, | ||
31 | "timer", timer_routine); | ||
32 | } | ||
33 | |||
34 | /* ++andreas: gettimeoffset fixed to check for pending interrupt */ | ||
35 | |||
36 | #define TICK_SIZE 10000 | ||
37 | |||
38 | /* This is always executed with interrupts disabled. */ | ||
39 | unsigned long atari_gettimeoffset (void) | ||
40 | { | ||
41 | unsigned long ticks, offset = 0; | ||
42 | |||
43 | /* read MFP timer C current value */ | ||
44 | ticks = mfp.tim_dt_c; | ||
45 | /* The probability of underflow is less than 2% */ | ||
46 | if (ticks > INT_TICKS - INT_TICKS / 50) | ||
47 | /* Check for pending timer interrupt */ | ||
48 | if (mfp.int_pn_b & (1 << 5)) | ||
49 | offset = TICK_SIZE; | ||
50 | |||
51 | ticks = INT_TICKS - ticks; | ||
52 | ticks = ticks * 10000L / INT_TICKS; | ||
53 | |||
54 | return ticks + offset; | ||
55 | } | ||
56 | |||
57 | |||
58 | static void mste_read(struct MSTE_RTC *val) | ||
59 | { | ||
60 | #define COPY(v) val->v=(mste_rtc.v & 0xf) | ||
61 | do { | ||
62 | COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; | ||
63 | COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; | ||
64 | COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; | ||
65 | COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; | ||
66 | COPY(year_tens) ; | ||
67 | /* prevent from reading the clock while it changed */ | ||
68 | } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); | ||
69 | #undef COPY | ||
70 | } | ||
71 | |||
72 | static void mste_write(struct MSTE_RTC *val) | ||
73 | { | ||
74 | #define COPY(v) mste_rtc.v=val->v | ||
75 | do { | ||
76 | COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; | ||
77 | COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; | ||
78 | COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; | ||
79 | COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; | ||
80 | COPY(year_tens) ; | ||
81 | /* prevent from writing the clock while it changed */ | ||
82 | } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); | ||
83 | #undef COPY | ||
84 | } | ||
85 | |||
86 | #define RTC_READ(reg) \ | ||
87 | ({ unsigned char __val; \ | ||
88 | (void) atari_writeb(reg,&tt_rtc.regsel); \ | ||
89 | __val = tt_rtc.data; \ | ||
90 | __val; \ | ||
91 | }) | ||
92 | |||
93 | #define RTC_WRITE(reg,val) \ | ||
94 | do { \ | ||
95 | atari_writeb(reg,&tt_rtc.regsel); \ | ||
96 | tt_rtc.data = (val); \ | ||
97 | } while(0) | ||
98 | |||
99 | |||
100 | #define HWCLK_POLL_INTERVAL 5 | ||
101 | |||
102 | int atari_mste_hwclk( int op, struct rtc_time *t ) | ||
103 | { | ||
104 | int hour, year; | ||
105 | int hr24=0; | ||
106 | struct MSTE_RTC val; | ||
107 | |||
108 | mste_rtc.mode=(mste_rtc.mode | 1); | ||
109 | hr24=mste_rtc.mon_tens & 1; | ||
110 | mste_rtc.mode=(mste_rtc.mode & ~1); | ||
111 | |||
112 | if (op) { | ||
113 | /* write: prepare values */ | ||
114 | |||
115 | val.sec_ones = t->tm_sec % 10; | ||
116 | val.sec_tens = t->tm_sec / 10; | ||
117 | val.min_ones = t->tm_min % 10; | ||
118 | val.min_tens = t->tm_min / 10; | ||
119 | hour = t->tm_hour; | ||
120 | if (!hr24) { | ||
121 | if (hour > 11) | ||
122 | hour += 20 - 12; | ||
123 | if (hour == 0 || hour == 20) | ||
124 | hour += 12; | ||
125 | } | ||
126 | val.hr_ones = hour % 10; | ||
127 | val.hr_tens = hour / 10; | ||
128 | val.day_ones = t->tm_mday % 10; | ||
129 | val.day_tens = t->tm_mday / 10; | ||
130 | val.mon_ones = (t->tm_mon+1) % 10; | ||
131 | val.mon_tens = (t->tm_mon+1) / 10; | ||
132 | year = t->tm_year - 80; | ||
133 | val.year_ones = year % 10; | ||
134 | val.year_tens = year / 10; | ||
135 | val.weekday = t->tm_wday; | ||
136 | mste_write(&val); | ||
137 | mste_rtc.mode=(mste_rtc.mode | 1); | ||
138 | val.year_ones = (year % 4); /* leap year register */ | ||
139 | mste_rtc.mode=(mste_rtc.mode & ~1); | ||
140 | } | ||
141 | else { | ||
142 | mste_read(&val); | ||
143 | t->tm_sec = val.sec_ones + val.sec_tens * 10; | ||
144 | t->tm_min = val.min_ones + val.min_tens * 10; | ||
145 | hour = val.hr_ones + val.hr_tens * 10; | ||
146 | if (!hr24) { | ||
147 | if (hour == 12 || hour == 12 + 20) | ||
148 | hour -= 12; | ||
149 | if (hour >= 20) | ||
150 | hour += 12 - 20; | ||
151 | } | ||
152 | t->tm_hour = hour; | ||
153 | 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_year = val.year_ones + val.year_tens * 10 + 80; | ||
156 | t->tm_wday = val.weekday; | ||
157 | } | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | int atari_tt_hwclk( int op, struct rtc_time *t ) | ||
162 | { | ||
163 | int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; | ||
164 | unsigned long flags; | ||
165 | unsigned char ctrl; | ||
166 | int pm = 0; | ||
167 | |||
168 | ctrl = RTC_READ(RTC_CONTROL); /* control registers are | ||
169 | * independent from the UIP */ | ||
170 | |||
171 | if (op) { | ||
172 | /* write: prepare values */ | ||
173 | |||
174 | sec = t->tm_sec; | ||
175 | min = t->tm_min; | ||
176 | hour = t->tm_hour; | ||
177 | day = t->tm_mday; | ||
178 | mon = t->tm_mon + 1; | ||
179 | year = t->tm_year - atari_rtc_year_offset; | ||
180 | wday = t->tm_wday + (t->tm_wday >= 0); | ||
181 | |||
182 | if (!(ctrl & RTC_24H)) { | ||
183 | if (hour > 11) { | ||
184 | pm = 0x80; | ||
185 | if (hour != 12) | ||
186 | hour -= 12; | ||
187 | } | ||
188 | else if (hour == 0) | ||
189 | hour = 12; | ||
190 | } | ||
191 | |||
192 | if (!(ctrl & RTC_DM_BINARY)) { | ||
193 | BIN_TO_BCD(sec); | ||
194 | BIN_TO_BCD(min); | ||
195 | BIN_TO_BCD(hour); | ||
196 | BIN_TO_BCD(day); | ||
197 | BIN_TO_BCD(mon); | ||
198 | BIN_TO_BCD(year); | ||
199 | if (wday >= 0) BIN_TO_BCD(wday); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /* 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 | * progress, registers 0..9 shouldn't be touched. | ||
206 | * 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 | * (50ms). This really should be enough, since the update cycle | ||
209 | * normally needs 2 ms. | ||
210 | * 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 | * additionally the RTC_SET bit is set to prevent an update cycle. | ||
213 | */ | ||
214 | |||
215 | while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { | ||
216 | current->state = TASK_INTERRUPTIBLE; | ||
217 | schedule_timeout(HWCLK_POLL_INTERVAL); | ||
218 | } | ||
219 | |||
220 | local_irq_save(flags); | ||
221 | RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); | ||
222 | if (!op) { | ||
223 | sec = RTC_READ( RTC_SECONDS ); | ||
224 | min = RTC_READ( RTC_MINUTES ); | ||
225 | hour = RTC_READ( RTC_HOURS ); | ||
226 | day = RTC_READ( RTC_DAY_OF_MONTH ); | ||
227 | mon = RTC_READ( RTC_MONTH ); | ||
228 | year = RTC_READ( RTC_YEAR ); | ||
229 | wday = RTC_READ( RTC_DAY_OF_WEEK ); | ||
230 | } | ||
231 | else { | ||
232 | RTC_WRITE( RTC_SECONDS, sec ); | ||
233 | RTC_WRITE( RTC_MINUTES, min ); | ||
234 | RTC_WRITE( RTC_HOURS, hour + pm); | ||
235 | RTC_WRITE( RTC_DAY_OF_MONTH, day ); | ||
236 | RTC_WRITE( RTC_MONTH, mon ); | ||
237 | RTC_WRITE( RTC_YEAR, year ); | ||
238 | if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); | ||
239 | } | ||
240 | RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); | ||
241 | local_irq_restore(flags); | ||
242 | |||
243 | if (!op) { | ||
244 | /* read: adjust values */ | ||
245 | |||
246 | if (hour & 0x80) { | ||
247 | hour &= ~0x80; | ||
248 | pm = 1; | ||
249 | } | ||
250 | |||
251 | if (!(ctrl & RTC_DM_BINARY)) { | ||
252 | BCD_TO_BIN(sec); | ||
253 | BCD_TO_BIN(min); | ||
254 | BCD_TO_BIN(hour); | ||
255 | BCD_TO_BIN(day); | ||
256 | BCD_TO_BIN(mon); | ||
257 | BCD_TO_BIN(year); | ||
258 | BCD_TO_BIN(wday); | ||
259 | } | ||
260 | |||
261 | if (!(ctrl & RTC_24H)) { | ||
262 | if (!pm && hour == 12) | ||
263 | hour = 0; | ||
264 | else if (pm && hour != 12) | ||
265 | hour += 12; | ||
266 | } | ||
267 | |||
268 | t->tm_sec = sec; | ||
269 | t->tm_min = min; | ||
270 | t->tm_hour = hour; | ||
271 | t->tm_mday = day; | ||
272 | t->tm_mon = mon - 1; | ||
273 | t->tm_year = year + atari_rtc_year_offset; | ||
274 | t->tm_wday = wday - 1; | ||
275 | } | ||
276 | |||
277 | return( 0 ); | ||
278 | } | ||
279 | |||
280 | |||
281 | int atari_mste_set_clock_mmss (unsigned long nowtime) | ||
282 | { | ||
283 | short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; | ||
284 | struct MSTE_RTC val; | ||
285 | unsigned char rtc_minutes; | ||
286 | |||
287 | mste_read(&val); | ||
288 | rtc_minutes= val.min_ones + val.min_tens * 10; | ||
289 | if ((rtc_minutes < real_minutes | ||
290 | ? real_minutes - rtc_minutes | ||
291 | : rtc_minutes - real_minutes) < 30) | ||
292 | { | ||
293 | val.sec_ones = real_seconds % 10; | ||
294 | val.sec_tens = real_seconds / 10; | ||
295 | val.min_ones = real_minutes % 10; | ||
296 | val.min_tens = real_minutes / 10; | ||
297 | mste_write(&val); | ||
298 | } | ||
299 | else | ||
300 | return -1; | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | int atari_tt_set_clock_mmss (unsigned long nowtime) | ||
305 | { | ||
306 | int retval = 0; | ||
307 | short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; | ||
308 | unsigned char save_control, save_freq_select, rtc_minutes; | ||
309 | |||
310 | save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ | ||
311 | RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); | ||
312 | |||
313 | save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ | ||
314 | RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); | ||
315 | |||
316 | rtc_minutes = RTC_READ (RTC_MINUTES); | ||
317 | if (!(save_control & RTC_DM_BINARY)) | ||
318 | BCD_TO_BIN (rtc_minutes); | ||
319 | |||
320 | /* Since we're only adjusting minutes and seconds, don't interfere | ||
321 | with hour overflow. This avoids messing with unknown time zones | ||
322 | but requires your RTC not to be off by more than 30 minutes. */ | ||
323 | if ((rtc_minutes < real_minutes | ||
324 | ? real_minutes - rtc_minutes | ||
325 | : rtc_minutes - real_minutes) < 30) | ||
326 | { | ||
327 | if (!(save_control & RTC_DM_BINARY)) | ||
328 | { | ||
329 | BIN_TO_BCD (real_seconds); | ||
330 | BIN_TO_BCD (real_minutes); | ||
331 | } | ||
332 | RTC_WRITE (RTC_SECONDS, real_seconds); | ||
333 | RTC_WRITE (RTC_MINUTES, real_minutes); | ||
334 | } | ||
335 | else | ||
336 | retval = -1; | ||
337 | |||
338 | RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); | ||
339 | RTC_WRITE (RTC_CONTROL, save_control); | ||
340 | return retval; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * Local variables: | ||
345 | * c-indent-level: 4 | ||
346 | * tab-width: 8 | ||
347 | * End: | ||
348 | */ | ||