Restored work-around for hangs when trying to use disk-based handlers
[tangerine.git] / arch / i386-pc / timer / ticks.c
blobd5c9b4eab62ff05ea7a697986bb1ddd83edeb338
1 //#include DEBUG 1
3 //#include <aros/debug.h>
4 #include <exec/types.h>
5 #include <proto/exec.h>
6 #include <asm/io.h>
8 #include <proto/timer.h>
10 #include "ticks.h"
12 const ULONG TIMER_RPROK = 3599597124UL;
14 ULONG tick2usec(ULONG tick)
16 ULONG ret, rest;
17 asm volatile("mull %3":"=d"(ret),"=a"(rest):"a"(TIMER_RPROK),"m"(tick));
18 ret+=rest>>31;
19 return ret;
22 ULONG usec2tick(ULONG usec)
24 ULONG ret;
25 asm volatile("movl $0,%%eax; divl %2":"=a"(ret):"d"(usec),"m"(TIMER_RPROK));
26 return ret;
29 void EClockUpdate(struct TimerBase *TimerBase)
31 ULONG time, diff;
33 Disable();
35 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
36 /* Latch the current time value */
38 outb(0x80, 0x43);
39 /* Read out current 16-bit time */
40 time = inb(0x42);
41 time += inb(0x42) << 8;
43 diff = (TimerBase->tb_prev_tick - time);
45 if (time > TimerBase->tb_prev_tick)
46 diff += 0x10000;
48 TimerBase->tb_prev_tick = time;
50 TimerBase->tb_ticks_total += diff;
51 TimerBase->tb_ticks_sec += diff;
52 TimerBase->tb_ticks_elapsed += diff;
54 if (TimerBase->tb_ticks_sec >= 1193180) {
55 TimerBase->tb_ticks_sec -= 1193180;
56 TimerBase->tb_CurrentTime.tv_secs++;
59 if (TimerBase->tb_ticks_elapsed >= 1193180) {
60 TimerBase->tb_ticks_elapsed -= 1193180;
61 TimerBase->tb_Elapsed.tv_secs++;
64 TimerBase->tb_Elapsed.tv_micro = tick2usec(TimerBase->tb_ticks_elapsed);
65 TimerBase->tb_CurrentTime.tv_micro = tick2usec(TimerBase->tb_ticks_sec);
67 Enable();
70 void EClockSet(struct TimerBase *TimerBase)
72 ULONG time;
74 TimerBase->tb_ticks_sec = usec2tick(TimerBase->tb_CurrentTime.tv_micro);
75 TimerBase->tb_ticks_total = TimerBase->tb_ticks_sec
76 + (UQUAD)TimerBase->tb_CurrentTime.tv_secs * 1193180;
78 /* Latch the current time value */
79 outb(0x80, 0x43);
80 /* Read out current 16-bit time */
81 time = inb(0x42);
82 time += inb(0x42) << 8;
83 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
85 TimerBase->tb_prev_tick = time;
88 void Timer0Setup(struct TimerBase *TimerBase)
90 struct timeval time;
91 ULONG delay = 23864;
92 struct timerequest *tr;
94 tr = (struct timerequest *)GetHead(&TimerBase->tb_Lists[TL_WAITVBL]);
96 if (tr)
98 time.tv_micro = tr->tr_time.tv_micro;
99 time.tv_secs = tr->tr_time.tv_secs;
101 EClockUpdate(TimerBase);
102 SubTime(&time, &TimerBase->tb_CurrentTime);
104 if ((LONG)time.tv_secs < 0)
106 delay = 0;
108 else if (time.tv_secs == 0)
110 if (time.tv_micro < 20000)
112 delay = usec2tick(time.tv_micro);
117 tr = (struct timerequest *)GetHead(&TimerBase->tb_Lists[TL_VBLANK]);
119 if (tr)
121 time.tv_micro = tr->tr_time.tv_micro;
122 time.tv_secs = tr->tr_time.tv_secs;
124 EClockUpdate(TimerBase);
125 SubTime(&time, &TimerBase->tb_Elapsed);
127 if ((LONG)time.tv_secs < 0)
129 delay = 0;
131 else if (time.tv_secs == 0)
133 if (time.tv_micro < 20000)
135 if (delay > usec2tick(time.tv_micro))
136 delay = usec2tick(time.tv_micro);
141 if (delay < 2) delay = 2;
143 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
144 outb(0x38, 0x43); /* Binary, mode 4, LSB&MSB */
145 outb(delay & 0xff, 0x40);
146 outb(delay >> 8, 0x40);