2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
5 Desc: Timer startup and device commands
9 #include <aros/debug.h>
11 /****************************************************************************************/
13 #include <aros/config.h>
14 #include <exec/devices.h>
15 #include <exec/interrupts.h>
16 #include <devices/timer.h>
17 #include <hardware/intbits.h>
18 #include <proto/exec.h>
19 #include <proto/execlock.h>
20 #include <proto/kernel.h>
21 #include <aros/symbolsets.h>
26 #define KernelBase LIBBASE->tb_KernelBase
28 /****************************************************************************************/
30 static void TimerInt(struct TimerBase
*TimerBase
, struct ExecBase
*SysBase
)
33 * Sync up with the hardware, we need the proper time value in order to
34 * process our requests correctly.
36 EClockUpdate(TimerBase
);
38 * Process MICROHZ requests.
39 * VBLANK is emulated by us, so we don't check it here. We always
40 * have one active request in this list, which will cause VBLANK checking.
42 handleMicroHZ(TimerBase
, SysBase
);
43 /* Request next interrupt from the hardware */
44 Timer0Setup(TimerBase
);
47 /****************************************************************************************/
49 static AROS_INTH1(ResetHandler
, struct TimerBase
*, LIBBASE
)
53 /* Set a mode that won't generate interrupts */
54 outb(CH0
|ACCESS_FULL
|MODE_ONESHOT
, PIT_CONTROL
);
61 /****************************************************************************************/
63 static int hw_Init(struct TimerBase
*LIBBASE
)
65 #if defined(__AROSEXEC_SMP__)
66 struct ExecLockBase
*ExecLockBase
;
67 if ((ExecLockBase
= OpenResource("execlock.resource")) != NULL
)
69 LIBBASE
->tb_ExecLockBase
= ExecLockBase
;
70 LIBBASE
->tb_ListLock
= AllocLock();
74 /* We must have kernel.resource */
75 D(bug("[Timer] KernelBase = 0x%p\n", KernelBase
));
79 /* Start up the interrupt server. We know that our HW timer is at IRQ 0 */
80 LIBBASE
->tb_TimerIRQHandle
= KrnAddIRQHandler(0, TimerInt
, LIBBASE
, SysBase
);
81 D(bug("[Timer] IRQ handle = 0x%p\n", LIBBASE
->tb_TimerIRQHandle
));
82 if (!LIBBASE
->tb_TimerIRQHandle
)
85 /* Install a reset handler */
86 LIBBASE
->tb_ResetHandler
.is_Node
.ln_Name
=
87 LIBBASE
->tb_Device
.dd_Library
.lib_Node
.ln_Name
;
88 LIBBASE
->tb_ResetHandler
.is_Code
= (VOID_FUNC
)ResetHandler
;
89 LIBBASE
->tb_ResetHandler
.is_Data
= LIBBASE
;
90 AddResetCallback(&LIBBASE
->tb_ResetHandler
);
92 D(bug("[Timer] Initializing hardware...\n"));
94 /* We have fixed EClock rate. VBlank will be emulated at 50Hz, can be changed at runtime. */
95 SysBase
->VBlankFrequency
= 50;
96 SysBase
->ex_EClockFrequency
= 1193180;
97 LIBBASE
->tb_eclock_rate
= 1193180;
98 LIBBASE
->tb_prev_tick
= 0xFFFF;
100 /* Start up the timer. Count the whole range for now. */
101 outb(CH0
|ACCESS_FULL
|MODE_SW_STROBE
, PIT_CONTROL
); /* Software strobe mode, 16-bit access */
102 ch_write(0xFFFF, PIT_CH0
);
106 * FIXME: This is not used by timer.device any more and must be removed.
107 * However PS/2 port driver uses polled microsecond delays via channel 2,
108 * and it relies on it being activated by us. This urgently needs to
111 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
112 outb(0xb4, 0x43); /* Binary mode on Timer2, count mode 2 */
113 outb(0x00, 0x42); /* We're counting whole range */
117 D(bug("[Timer] Starting VBlank emulation (%u Hz)...\n", SysBase
->VBlankFrequency
));
119 LIBBASE
->tb_vblank_timerequest
.tr_node
.io_Command
= TR_ADDREQUEST
;
120 LIBBASE
->tb_vblank_timerequest
.tr_node
.io_Device
= &LIBBASE
->tb_Device
;
121 LIBBASE
->tb_vblank_timerequest
.tr_node
.io_Unit
= (struct Unit
*)UNIT_MICROHZ
;
122 LIBBASE
->tb_vblank_timerequest
.tr_time
.tv_secs
= 0;
123 LIBBASE
->tb_vblank_timerequest
.tr_time
.tv_micro
= 1000000 / SysBase
->VBlankFrequency
;
125 SendIO(&LIBBASE
->tb_vblank_timerequest
.tr_node
);
127 D(bug("[Timer] Done\n"));
132 /****************************************************************************************/
134 static int hw_Expunge(struct TimerBase
*LIBBASE
)
136 KrnRemIRQHandler(LIBBASE
->tb_TimerIRQHandle
);
137 RemResetCallback(&LIBBASE
->tb_ResetHandler
);
142 /****************************************************************************************/
144 ADD2INITLIB(hw_Init
, 0)
145 ADD2EXPUNGELIB(hw_Expunge
, 0)