Revision f6503059 hw/m48t59.c
b/hw/m48t59.c | ||
---|---|---|
53 | 53 |
time_t time_offset; |
54 | 54 |
time_t stop_time; |
55 | 55 |
/* Alarm & watchdog */ |
56 |
time_t alarm;
|
|
56 |
struct tm alarm;
|
|
57 | 57 |
struct QEMUTimer *alrm_timer; |
58 | 58 |
struct QEMUTimer *wd_timer; |
59 | 59 |
/* NVRAM storage */ |
... | ... | |
74 | 74 |
return ((BCD >> 4) * 10) + (BCD & 0x0F); |
75 | 75 |
} |
76 | 76 |
|
77 |
/* RTC management helpers */ |
|
78 |
static void get_time (m48t59_t *NVRAM, struct tm *tm) |
|
79 |
{ |
|
80 |
time_t t; |
|
81 |
|
|
82 |
t = time(NULL) + NVRAM->time_offset; |
|
83 |
#ifdef _WIN32 |
|
84 |
memcpy(tm,localtime(&t),sizeof(*tm)); |
|
85 |
#else |
|
86 |
if (rtc_utc) |
|
87 |
gmtime_r (&t, tm); |
|
88 |
else |
|
89 |
localtime_r (&t, tm) ; |
|
90 |
#endif |
|
91 |
} |
|
92 |
|
|
93 |
static void set_time (m48t59_t *NVRAM, struct tm *tm) |
|
94 |
{ |
|
95 |
time_t now, new_time; |
|
96 |
|
|
97 |
new_time = mktime(tm); |
|
98 |
now = time(NULL); |
|
99 |
NVRAM->time_offset = new_time - now; |
|
100 |
} |
|
101 |
|
|
102 | 77 |
/* Alarm management */ |
103 | 78 |
static void alarm_cb (void *opaque) |
104 | 79 |
{ |
105 |
struct tm tm, tm_now;
|
|
80 |
struct tm tm; |
|
106 | 81 |
uint64_t next_time; |
107 | 82 |
m48t59_t *NVRAM = opaque; |
108 | 83 |
|
... | ... | |
111 | 86 |
(NVRAM->buffer[0x1FF4] & 0x80) == 0 && |
112 | 87 |
(NVRAM->buffer[0x1FF3] & 0x80) == 0 && |
113 | 88 |
(NVRAM->buffer[0x1FF2] & 0x80) == 0) { |
114 |
/* Repeat once a month */ |
|
115 |
get_time(NVRAM, &tm_now); |
|
116 |
memcpy(&tm, &tm_now, sizeof(struct tm)); |
|
117 |
tm.tm_mon++; |
|
118 |
if (tm.tm_mon == 13) { |
|
119 |
tm.tm_mon = 1; |
|
120 |
tm.tm_year++; |
|
121 |
} |
|
122 |
next_time = mktime(&tm); |
|
89 |
/* Repeat once a month */ |
|
90 |
qemu_get_timedate(&tm, NVRAM->time_offset); |
|
91 |
tm.tm_mon++; |
|
92 |
if (tm.tm_mon == 13) { |
|
93 |
tm.tm_mon = 1; |
|
94 |
tm.tm_year++; |
|
95 |
} |
|
96 |
next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset; |
|
123 | 97 |
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && |
124 | 98 |
(NVRAM->buffer[0x1FF4] & 0x80) == 0 && |
125 | 99 |
(NVRAM->buffer[0x1FF3] & 0x80) == 0 && |
126 | 100 |
(NVRAM->buffer[0x1FF2] & 0x80) == 0) { |
127 |
/* Repeat once a day */
|
|
128 |
next_time = 24 * 60 * 60 + mktime(&tm_now);
|
|
101 |
/* Repeat once a day */
|
|
102 |
next_time = 24 * 60 * 60;
|
|
129 | 103 |
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && |
130 | 104 |
(NVRAM->buffer[0x1FF4] & 0x80) != 0 && |
131 | 105 |
(NVRAM->buffer[0x1FF3] & 0x80) == 0 && |
132 | 106 |
(NVRAM->buffer[0x1FF2] & 0x80) == 0) { |
133 |
/* Repeat once an hour */
|
|
134 |
next_time = 60 * 60 + mktime(&tm_now);
|
|
107 |
/* Repeat once an hour */
|
|
108 |
next_time = 60 * 60;
|
|
135 | 109 |
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && |
136 | 110 |
(NVRAM->buffer[0x1FF4] & 0x80) != 0 && |
137 | 111 |
(NVRAM->buffer[0x1FF3] & 0x80) != 0 && |
138 | 112 |
(NVRAM->buffer[0x1FF2] & 0x80) == 0) { |
139 |
/* Repeat once a minute */
|
|
140 |
next_time = 60 + mktime(&tm_now);
|
|
113 |
/* Repeat once a minute */
|
|
114 |
next_time = 60;
|
|
141 | 115 |
} else { |
142 |
/* Repeat once a second */
|
|
143 |
next_time = 1 + mktime(&tm_now);
|
|
116 |
/* Repeat once a second */
|
|
117 |
next_time = 1;
|
|
144 | 118 |
} |
145 |
qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); |
|
119 |
qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock(vm_clock) + |
|
120 |
next_time * 1000); |
|
146 | 121 |
qemu_set_irq(NVRAM->IRQ, 0); |
147 | 122 |
} |
148 | 123 |
|
124 |
static void set_alarm (m48t59_t *NVRAM) |
|
125 |
{ |
|
126 |
int diff; |
|
127 |
if (NVRAM->alrm_timer != NULL) { |
|
128 |
qemu_del_timer(NVRAM->alrm_timer); |
|
129 |
diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset; |
|
130 |
if (diff > 0) |
|
131 |
qemu_mod_timer(NVRAM->alrm_timer, diff * 1000); |
|
132 |
} |
|
133 |
} |
|
149 | 134 |
|
150 |
static void get_alarm (m48t59_t *NVRAM, struct tm *tm) |
|
135 |
/* RTC management helpers */ |
|
136 |
static inline void get_time (m48t59_t *NVRAM, struct tm *tm) |
|
151 | 137 |
{ |
152 |
#ifdef _WIN32 |
|
153 |
memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm)); |
|
154 |
#else |
|
155 |
if (rtc_utc) |
|
156 |
gmtime_r (&NVRAM->alarm, tm); |
|
157 |
else |
|
158 |
localtime_r (&NVRAM->alarm, tm); |
|
159 |
#endif |
|
138 |
qemu_get_timedate(tm, NVRAM->time_offset); |
|
160 | 139 |
} |
161 | 140 |
|
162 |
static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
|
|
141 |
static void set_time (m48t59_t *NVRAM, struct tm *tm)
|
|
163 | 142 |
{ |
164 |
NVRAM->alarm = mktime(tm); |
|
165 |
if (NVRAM->alrm_timer != NULL) { |
|
166 |
qemu_del_timer(NVRAM->alrm_timer); |
|
167 |
if (NVRAM->alarm - time(NULL) > 0) |
|
168 |
qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); |
|
169 |
} |
|
143 |
NVRAM->time_offset = qemu_timedate_diff(tm); |
|
144 |
set_alarm(NVRAM); |
|
170 | 145 |
} |
171 | 146 |
|
172 | 147 |
/* Watchdog management */ |
... | ... | |
229 | 204 |
/* alarm seconds */ |
230 | 205 |
tmp = fromBCD(val & 0x7F); |
231 | 206 |
if (tmp >= 0 && tmp <= 59) { |
232 |
get_alarm(NVRAM, &tm); |
|
233 |
tm.tm_sec = tmp; |
|
207 |
NVRAM->alarm.tm_sec = tmp; |
|
234 | 208 |
NVRAM->buffer[0x1FF2] = val; |
235 |
set_alarm(NVRAM, &tm);
|
|
209 |
set_alarm(NVRAM); |
|
236 | 210 |
} |
237 | 211 |
break; |
238 | 212 |
case 0x1FF3: |
239 | 213 |
/* alarm minutes */ |
240 | 214 |
tmp = fromBCD(val & 0x7F); |
241 | 215 |
if (tmp >= 0 && tmp <= 59) { |
242 |
get_alarm(NVRAM, &tm); |
|
243 |
tm.tm_min = tmp; |
|
216 |
NVRAM->alarm.tm_min = tmp; |
|
244 | 217 |
NVRAM->buffer[0x1FF3] = val; |
245 |
set_alarm(NVRAM, &tm);
|
|
218 |
set_alarm(NVRAM); |
|
246 | 219 |
} |
247 | 220 |
break; |
248 | 221 |
case 0x1FF4: |
249 | 222 |
/* alarm hours */ |
250 | 223 |
tmp = fromBCD(val & 0x3F); |
251 | 224 |
if (tmp >= 0 && tmp <= 23) { |
252 |
get_alarm(NVRAM, &tm); |
|
253 |
tm.tm_hour = tmp; |
|
225 |
NVRAM->alarm.tm_hour = tmp; |
|
254 | 226 |
NVRAM->buffer[0x1FF4] = val; |
255 |
set_alarm(NVRAM, &tm);
|
|
227 |
set_alarm(NVRAM); |
|
256 | 228 |
} |
257 | 229 |
break; |
258 | 230 |
case 0x1FF5: |
259 | 231 |
/* alarm date */ |
260 | 232 |
tmp = fromBCD(val & 0x1F); |
261 | 233 |
if (tmp != 0) { |
262 |
get_alarm(NVRAM, &tm); |
|
263 |
tm.tm_mday = tmp; |
|
234 |
NVRAM->alarm.tm_mday = tmp; |
|
264 | 235 |
NVRAM->buffer[0x1FF5] = val; |
265 |
set_alarm(NVRAM, &tm);
|
|
236 |
set_alarm(NVRAM); |
|
266 | 237 |
} |
267 | 238 |
break; |
268 | 239 |
case 0x1FF6: |
... | ... | |
288 | 259 |
tm.tm_sec = tmp; |
289 | 260 |
set_time(NVRAM, &tm); |
290 | 261 |
} |
291 |
if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) { |
|
262 |
if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
|
|
292 | 263 |
if (val & 0x80) { |
293 | 264 |
NVRAM->stop_time = time(NULL); |
294 | 265 |
} else { |
... | ... | |
296 | 267 |
NVRAM->stop_time = 0; |
297 | 268 |
} |
298 | 269 |
} |
299 |
NVRAM->buffer[addr] = val & 0x80; |
|
270 |
NVRAM->buffer[addr] = val & 0x80;
|
|
300 | 271 |
break; |
301 | 272 |
case 0x1FFA: |
302 | 273 |
case 0x07FA: |
... | ... | |
682 | 653 |
s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); |
683 | 654 |
} |
684 | 655 |
s->lock = 0; |
656 |
qemu_get_timedate(&s->alarm, 0); |
|
685 | 657 |
|
686 | 658 |
qemu_register_reset(m48t59_reset, s); |
687 | 659 |
save_base = mem_base ? mem_base : io_base; |
Also available in: Unified diff