#include "pc.h"
#include "apic.h"
#include "isa.h"
-#include "hpet_emul.h"
#include "mc146818rtc.h"
//#define DEBUG_CMOS
#define REG_B_UIE 0x10
#define REG_B_SQWE 0x08
#define REG_B_DM 0x04
+#define REG_B_24H 0x02
#define REG_C_UF 0x10
#define REG_C_IRQF 0x80
QEMUTimer *second_timer2;
} RTCState;
-static void rtc_irq_raise(qemu_irq irq)
-{
- /* When HPET is operating in legacy mode, RTC interrupts are disabled
- * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
- * mode is established while interrupt is raised. We want it to
- * be lowered in any case
- */
-#if defined TARGET_I386
- if (!hpet_in_legacy_mode())
-#endif
- qemu_irq_raise(irq);
-}
-
static void rtc_set_time(RTCState *s);
static void rtc_copy_date(RTCState *s);
} else {
/* divide each RTC interval to 2 - 8 smaller intervals */
int c = MIN(s->irq_coalesced, 7) + 1;
- int64_t next_clock = qemu_get_clock(rtc_clock) +
+ int64_t next_clock = qemu_get_clock_ns(rtc_clock) +
muldiv64(s->period / c, get_ticks_per_sec(), 32768);
qemu_mod_timer(s->coalesced_timer, next_clock);
}
apic_reset_irq_delivered();
s->cmos_data[RTC_REG_C] |= 0xc0;
DPRINTF_C("cmos: injecting from timer\n");
- rtc_irq_raise(s->irq);
+ qemu_irq_raise(s->irq);
if (apic_get_irq_delivered()) {
s->irq_coalesced--;
DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
{
int period_code, period;
int64_t cur_clock, next_irq_clock;
- int enable_pie;
period_code = s->cmos_data[RTC_REG_A] & 0x0f;
-#if defined TARGET_I386
- /* disable periodic timer if hpet is in legacy mode, since interrupts are
- * disabled anyway.
- */
- enable_pie = !hpet_in_legacy_mode();
-#else
- enable_pie = 1;
-#endif
if (period_code != 0
- && (((s->cmos_data[RTC_REG_B] & REG_B_PIE) && enable_pie)
+ && ((s->cmos_data[RTC_REG_B] & REG_B_PIE)
|| ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
if (period_code <= 2)
period_code += 7;
if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
s->irq_reinject_on_ack_count = 0;
apic_reset_irq_delivered();
- rtc_irq_raise(s->irq);
+ qemu_irq_raise(s->irq);
if (!apic_get_irq_delivered()) {
s->irq_coalesced++;
rtc_coalesced_timer_update(s);
}
} else
#endif
- rtc_irq_raise(s->irq);
+ qemu_irq_raise(s->irq);
}
if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
/* Not square wave at all but we don't want 2048Hz interrupts!
case RTC_SECONDS_ALARM:
case RTC_MINUTES_ALARM:
case RTC_HOURS_ALARM:
- /* XXX: not supported */
s->cmos_data[s->cmos_index] = data;
break;
case RTC_SECONDS:
/* UIP bit is read only */
s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
(s->cmos_data[RTC_REG_A] & REG_A_UIP);
- rtc_timer_update(s, qemu_get_clock(rtc_clock));
+ rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
break;
case RTC_REG_B:
if (data & REG_B_SET) {
rtc_set_time(s);
}
}
- s->cmos_data[RTC_REG_B] = data;
- rtc_timer_update(s, qemu_get_clock(rtc_clock));
+ if (((s->cmos_data[RTC_REG_B] ^ data) & (REG_B_DM | REG_B_24H)) &&
+ !(data & REG_B_SET)) {
+ /* If the time format has changed and not in set mode,
+ update the registers immediately. */
+ s->cmos_data[RTC_REG_B] = data;
+ rtc_copy_date(s);
+ } else {
+ s->cmos_data[RTC_REG_B] = data;
+ }
+ rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
break;
case RTC_REG_C:
case RTC_REG_D:
tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
- if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
+ if (!(s->cmos_data[RTC_REG_B] & REG_B_24H) &&
(s->cmos_data[RTC_HOURS] & 0x80)) {
tm->tm_hour += 12;
}
s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
- if (s->cmos_data[RTC_REG_B] & 0x02) {
+ if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
/* 24 hour format */
s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
} else {
/* check alarm */
if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
- s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
+ rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) &&
((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
- s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
+ rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) &&
((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
- s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
+ rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) {
s->cmos_data[RTC_REG_C] |= 0xa0;
- rtc_irq_raise(s->irq);
+ qemu_irq_raise(s->irq);
}
}
/* update ended interrupt */
s->cmos_data[RTC_REG_C] |= REG_C_UF;
if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
- s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
- rtc_irq_raise(s->irq);
+ s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+ qemu_irq_raise(s->irq);
}
/* clear update in progress bit */
{
RTCState *s = DO_UPCAST(RTCState, dev, dev);
int base = 0x70;
- int isairq = 8;
-
- isa_init_irq(dev, &s->irq, isairq);
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
rtc_set_date_from_host(dev);
- s->periodic_timer = qemu_new_timer(rtc_clock, rtc_periodic_timer, s);
+ s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
#ifdef TARGET_I386
if (rtc_td_hack)
s->coalesced_timer =
- qemu_new_timer(rtc_clock, rtc_coalesced_timer, s);
+ qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
#endif
- s->second_timer = qemu_new_timer(rtc_clock, rtc_update_second, s);
- s->second_timer2 = qemu_new_timer(rtc_clock, rtc_update_second2, s);
+ s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
+ s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
s->next_second_time =
- qemu_get_clock(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
+ qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
qemu_mod_timer(s->second_timer2, s->next_second_time);
register_ioport_write(base, 2, 1, cmos_ioport_write, s);
register_ioport_read(base, 2, 1, cmos_ioport_read, s);
+ isa_init_ioport_range(dev, base, 2);
qdev_set_legacy_instance_id(&dev->qdev, base, 2);
qemu_register_reset(rtc_reset, s);
return 0;
}
-ISADevice *rtc_init(int base_year)
+ISADevice *rtc_init(int base_year, qemu_irq intercept_irq)
{
ISADevice *dev;
+ RTCState *s;
dev = isa_create("mc146818rtc");
+ s = DO_UPCAST(RTCState, dev, dev);
qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
qdev_init_nofail(&dev->qdev);
+ if (intercept_irq) {
+ s->irq = intercept_irq;
+ } else {
+ isa_init_irq(dev, &s->irq, RTC_ISA_IRQ);
+ }
return dev;
}