static void rtc_periodic_timer(void *opaque) { RTCState *s = opaque; periodic_timer_update(s, s->next_periodic_time); s->cmos_data[RTC_REG_C] |= REG_C_PF; if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= REG_C_IRQF; #ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_SLEW) { if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) s->irq_reinject_on_ack_count = 0; apic_reset_irq_delivered(); qemu_irq_raise(s->irq); if (!apic_get_irq_delivered()) { s->irq_coalesced++; rtc_coalesced_timer_update(s); DPRINTF_C("cmos: coalesced irqs increased to %d\n", s->irq_coalesced); } } else #endif 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! Must be seen as a pulse. */ qemu_irq_raise(s->sqw_irq); } }
static void rtc_periodic_timer(void *opaque) { RTCState *s = opaque; periodic_timer_update(s, s->next_periodic_time); s->cmos_data[RTC_REG_C] |= REG_C_PF; if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= REG_C_IRQF; #ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) s->irq_reinject_on_ack_count = 0; apic_reset_irq_delivered(); qemu_irq_raise(s->irq); if (!apic_get_irq_delivered()) { s->irq_coalesced++; rtc_coalesced_timer_update(s); DPRINTF_C("cmos: coalesced irqs increased to %d\n", s->irq_coalesced); } } else #endif qemu_irq_raise(s->irq); } }
static void rtc_notify_clock_reset(Notifier *notifier, void *data) { RTCState *s = container_of(notifier, RTCState, clock_reset_notifier); int64_t now = *(int64_t *)data; rtc_set_date_from_host(ISA_DEVICE(s)); periodic_timer_update(s, now); check_update_timer(s); #ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); } #endif }
static void cmos_ioport_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { RTCState *s = opaque; if ((addr & 1) == 0) { s->cmos_index = data & 0x7f; } else { CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n", s->cmos_index, data); switch(s->cmos_index) { case RTC_SECONDS_ALARM: case RTC_MINUTES_ALARM: case RTC_HOURS_ALARM: s->cmos_data[s->cmos_index] = data; check_update_timer(s); break; case RTC_IBM_PS2_CENTURY_BYTE: s->cmos_index = RTC_CENTURY; /* fall through */ case RTC_CENTURY: case RTC_SECONDS: case RTC_MINUTES: case RTC_HOURS: case RTC_DAY_OF_WEEK: case RTC_DAY_OF_MONTH: case RTC_MONTH: case RTC_YEAR: s->cmos_data[s->cmos_index] = data; /* if in set mode, do not update the time */ if (rtc_running(s)) { rtc_set_time(s); check_update_timer(s); } break; case RTC_REG_A: if ((data & 0x60) == 0x60) { if (rtc_running(s)) { rtc_update_time(s); } /* What happens to UIP when divider reset is enabled is * unclear from the datasheet. Shouldn't matter much * though. */ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) && (data & 0x70) <= 0x20) { /* when the divider reset is removed, the first update cycle * begins one-half second later*/ if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { s->offset = 500000000; rtc_set_time(s); } s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; } /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); check_update_timer(s); break; case RTC_REG_B: if (data & REG_B_SET) { /* update cmos to when the rtc was stopping */ if (rtc_running(s)) { rtc_update_time(s); } /* set mode: reset UIP mode */ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; data &= ~REG_B_UIE; } else { /* if disabling set mode, update the time */ if ((s->cmos_data[RTC_REG_B] & REG_B_SET) && (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) { s->offset = get_guest_rtc_ns(s) % NSEC_PER_SEC; rtc_set_time(s); } } /* if an interrupt flag is already set when the interrupt * becomes enabled, raise an interrupt immediately. */ if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) { s->cmos_data[RTC_REG_C] |= REG_C_IRQF; qemu_irq_raise(s->irq); } else { s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF; qemu_irq_lower(s->irq); } s->cmos_data[RTC_REG_B] = data; periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); check_update_timer(s); break; case RTC_REG_C: case RTC_REG_D: /* cannot write to them */ break; default: s->cmos_data[s->cmos_index] = data; break; } } }