2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
5 Desc: Timer startup and device commands
8 /****************************************************************************************/
14 - CIAA-A: normal timer jobs (microhz/e-clock)
15 - CIAA-B: E-clock counter (can move to CIAB-A or CIAB-B)
16 - vblank interrupt used for vblank timer unit
18 Unit conversions and misuse of tv_sec/tv_usec fields probably looks strange..
22 #include <aros/debug.h>
24 #include <aros/kernel.h>
25 #include <exec/types.h>
27 #include <exec/errors.h>
28 #include <exec/devices.h>
29 #include <exec/alerts.h>
30 #include <exec/initializers.h>
31 #include <devices/timer.h>
32 #include <hardware/intbits.h>
33 #include <hardware/cia.h>
34 #include <graphics/gfxbase.h>
36 #include <proto/exec.h>
37 #include <proto/kernel.h>
38 #include <proto/timer.h>
39 #include <proto/cia.h>
40 #include <proto/battclock.h>
42 #include <aros/symbolsets.h>
44 #include LC_LIBDEFS_FILE
46 #include <timer_intern.h>
47 #include <timer_platform.h>
49 AROS_INTP(ciab_eclock
);
50 AROS_INTP(ciaint_timer
);
53 /****************************************************************************************/
55 static void start_eclock(struct TimerBase
*tb
, UWORD cnt
)
57 *tb
->tb_eclock_cr
= 0x00;
58 SetICR(tb
->tb_eclock_res
, 1 << tb
->tb_eclock_intbit
);
59 // start timer in continuous mode
60 *tb
->tb_eclock_lo
= cnt
;
61 *tb
->tb_eclock_hi
= cnt
>> 8;
62 *tb
->tb_eclock_cr
|= 0x10;
63 *tb
->tb_eclock_cr
|= 0x01;
65 static void set_eclock(struct TimerBase
*tb
, WORD intbit
)
67 WORD cia
= intbit
>> 1;
69 tb
->tb_eclock_cia
= (struct CIA
*)(cia
? 0xbfd000 : 0xbfe001);
70 tb
->tb_eclock_cr
= (UBYTE
*)tb
->tb_eclock_cia
+ (intbit
? 0xf00 : 0xe00);
71 tb
->tb_eclock_lo
= (UBYTE
*)tb
->tb_eclock_cia
+ (intbit
? 0x600 : 0x400);
72 tb
->tb_eclock_hi
= tb
->tb_eclock_lo
+ 0x100;
73 tb
->tb_eclock_intbit
= intbit
;
74 tb
->tb_eclock_res
= tb
->tb_cia
[cia
];
77 static void TimerHook(struct Resource
*cia
, struct TimerBase
*tb
, WORD iCRBit
)
83 if (tb
->tb_eclock_res
!= cia
|| tb
->tb_eclock_intbit
!= iCRBit
)
85 /* We are in Disabled state already
86 * Someone wants to allocate our eclock timer
87 * Check if we have any available timers left..
89 D(bug("someone wants our timer %x %d\n", cia
, iCRBit
));
90 for (cnt
= 1; cnt
< 4; cnt
++) {
91 if (!AddICRVector(tb
->tb_cia
[cnt
>> 1], cnt
& 1, &tb
->tb_ciaint_eclock
))
95 D(bug("no free timers\n"));
99 D(bug("e-clock timer moved to %d\n", cnt
));
101 hi
= *tb
->tb_eclock_hi
;
102 lo
= *tb
->tb_eclock_lo
;
103 if (hi
== *tb
->tb_eclock_hi
)
106 intactive
= (SetICR(tb
->tb_eclock_res
, 0) & (1 << tb
->tb_eclock_intbit
)) != 0;
108 // re-read, there may have been wrap-around
110 hi
= *tb
->tb_eclock_hi
;
111 lo
= *tb
->tb_eclock_lo
;
112 if (hi
== *tb
->tb_eclock_hi
)
116 *tb
->tb_eclock_cr
= 0x00;
117 RemICRVector(tb
->tb_eclock_res
, tb
->tb_eclock_intbit
, &tb
->tb_ciaint_eclock
);
118 set_eclock (tb
, cnt
);
119 start_eclock (tb
, (hi
<< 8) | lo
);
121 SetICR(tb
->tb_eclock_res
, 0x80 | (1 << tb
->tb_eclock_intbit
));
124 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR LIBBASE
)
126 struct Interrupt
*inter
;
127 struct Interrupt fakeinter
;
128 struct BattClockBase
*BattClockBase
;
129 struct GfxBase
*GfxBase
;
131 GfxBase
= TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS
);
135 LIBBASE
->tb_eclock_rate
= (GfxBase
->DisplayFlags
& REALLY_PAL
) ? 709379 : 715909;
136 LIBBASE
->tb_vblank_rate
= (GfxBase
->DisplayFlags
& PAL
) ? 50 : 60;
137 LIBBASE
->tb_vblank_micros
= 1000000 / LIBBASE
->tb_vblank_rate
;
138 SysBase
->ex_EClockFrequency
= LIBBASE
->tb_eclock_rate
;
139 LIBBASE
->tb_eclock_micro_mult
= (GfxBase
->DisplayFlags
& REALLY_PAL
) ? 92385 : 91542;
140 LIBBASE
->tb_micro_eclock_mult
= (GfxBase
->DisplayFlags
& REALLY_PAL
) ? 23245 : 23459;
142 CloseLibrary((struct Library
*)GfxBase
);
144 BattClockBase
= OpenResource("battclock.resource");
146 LIBBASE
->tb_CurrentTime
.tv_secs
= ReadBattClock();
148 /* Initialise the lists */
149 NEWLIST(&LIBBASE
->tb_Lists
[UNIT_VBLANK
]);
150 NEWLIST(&LIBBASE
->tb_Lists
[UNIT_MICROHZ
]);
152 inter
= &LIBBASE
->tb_vbint
;
153 inter
->is_Code
= (APTR
)cia_vbint
;
154 inter
->is_Data
= LIBBASE
;
155 inter
->is_Node
.ln_Name
= "timer.device VBlank";
156 inter
->is_Node
.ln_Pri
= 20;
157 inter
->is_Node
.ln_Type
= NT_INTERRUPT
;
158 AddIntServer(INTB_VERTB
, inter
);
160 LIBBASE
->tb_cia
[0] = OpenResource("ciaa.resource");
161 LIBBASE
->tb_cia
[1] = OpenResource("ciab.resource");
162 if (!LIBBASE
->tb_cia
[0] || !LIBBASE
->tb_cia
[1])
163 Alert(AT_DeadEnd
| AG_OpenRes
| AO_CIARsrc
);
164 LIBBASE
->tb_eclock_res
= LIBBASE
->tb_micro_res
= LIBBASE
->tb_cia
[0];
166 /* CIA-A timer A = microhz */
167 LIBBASE
->tb_micro_cia
= (struct CIA
*)0xbfe001;
168 LIBBASE
->tb_micro_cr
= (UBYTE
*)LIBBASE
->tb_micro_cia
+ 0xe00;
169 LIBBASE
->tb_micro_lo
= (UBYTE
*)LIBBASE
->tb_micro_cia
+ 0x400;
170 LIBBASE
->tb_micro_hi
= (UBYTE
*)LIBBASE
->tb_micro_cia
+ 0x500;
171 LIBBASE
->tb_micro_intbit
= 0;
173 inter
= &LIBBASE
->tb_ciaint_timer
;
174 inter
->is_Node
.ln_Pri
= 0;
175 inter
->is_Node
.ln_Type
= NT_INTERRUPT
;
176 inter
->is_Node
.ln_Name
= "timer.device microhz";
177 inter
->is_Code
= (APTR
)ciaint_timer
;
178 inter
->is_Data
= LIBBASE
;
180 /* CIA-A timer B = E-Clock */
181 set_eclock (LIBBASE
, 1);
183 inter
= &LIBBASE
->tb_ciaint_eclock
;
184 inter
->is_Node
.ln_Pri
= 0;
185 inter
->is_Node
.ln_Type
= NT_INTERRUPT
;
186 inter
->is_Node
.ln_Name
= "timer.device eclock";
187 inter
->is_Code
= (APTR
)ciab_eclock
;
188 inter
->is_Data
= LIBBASE
;
192 if (AddICRVector(LIBBASE
->tb_micro_res
, LIBBASE
->tb_micro_intbit
, &LIBBASE
->tb_ciaint_timer
))
193 Alert(AT_DeadEnd
| AG_NoMemory
| AO_CIARsrc
);
194 *LIBBASE
->tb_micro_cr
= 0x08; // one-shot
195 SetICR(LIBBASE
->tb_micro_res
, 1 << LIBBASE
->tb_micro_intbit
);
197 if (AddICRVector(LIBBASE
->tb_eclock_res
, LIBBASE
->tb_eclock_intbit
, &LIBBASE
->tb_ciaint_eclock
))
198 Alert(AT_DeadEnd
| AG_NoMemory
| AO_CIARsrc
);
199 start_eclock (LIBBASE
, 0xffff);
201 /* Emulate AOS 2.0+ feature which moves 2.0+ only E-clock timer out of
202 * the way if some other (Usually 1.x) program assumes CIAA-B is always
203 * free and wants to allocate it. This is m68k AROS hack, there is no
206 fakeinter
.is_Code
= (APTR
)TimerHook
;
207 fakeinter
.is_Data
= LIBBASE
;
208 AddICRVector(LIBBASE
->tb_cia
[0], -1, &fakeinter
);
209 AddICRVector(LIBBASE
->tb_cia
[1], -1, &fakeinter
);
213 D(bug("timer.device init\n"));
218 /****************************************************************************************/
220 static int GM_UNIQUENAME(Open
)
222 LIBBASETYPEPTR LIBBASE
,
223 struct timerequest
*tr
,
234 case UNIT_WAITECLOCK
:
235 tr
->tr_node
.io_Error
= 0;
236 tr
->tr_node
.io_Unit
= (struct Unit
*)unitNum
;
237 tr
->tr_node
.io_Device
= (struct Device
*)LIBBASE
;
241 tr
->tr_node
.io_Error
= IOERR_OPENFAIL
;
247 /****************************************************************************************/
249 static int GM_UNIQUENAME(Expunge
)(LIBBASETYPEPTR LIBBASE
)
252 RemIntServer(INTB_VERTB
, &LIBBASE
->tb_vbint
);
253 RemICRVector(LIBBASE
->tb_micro_res
, LIBBASE
->tb_micro_intbit
, &LIBBASE
->tb_ciaint_timer
);
254 RemICRVector(LIBBASE
->tb_eclock_res
, LIBBASE
->tb_eclock_intbit
, &LIBBASE
->tb_ciaint_eclock
);
259 /****************************************************************************************/
261 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
262 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
263 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge
), 0)