static void rtc_update_second2(void *opaque) { RTCState *s = opaque; if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { rtc_copy_date(s); } /* check alarm */ if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 || rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) && ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 || rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) && ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) { s->cmos_data[RTC_REG_C] |= 0xa0; 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; qemu_irq_raise(s->irq); } /* clear update in progress bit */ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; s->next_second_time += get_ticks_per_sec(); qemu_mod_timer(s->second_timer, s->next_second_time); }
static void rtc_get_time(RTCState *s, struct tm *tm) { 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] & REG_B_24H)) { tm->tm_hour %= 12; if (s->cmos_data[RTC_HOURS] & 0x80) { tm->tm_hour += 12; } } tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1; tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year + rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900; }
static void rtc_set_time(RTCState *s) { struct tm *tm = &s->current_tm; 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] & REG_B_24H) && (s->cmos_data[RTC_HOURS] & 0x80)) { tm->tm_hour += 12; } tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1; tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900; rtc_change_mon_event(tm); }
static uint64_t get_next_alarm(RTCState *s) { int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec; int32_t hour, min, sec; rtc_update_time(s); alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]); alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]); alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]); alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour); cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]); cur_hour = convert_hour(s, cur_hour); if (alarm_hour == -1) { alarm_hour = cur_hour; if (alarm_min == -1) { alarm_min = cur_min; if (alarm_sec == -1) { alarm_sec = cur_sec + 1; } else if (cur_sec > alarm_sec) { alarm_min++; } } else if (cur_min == alarm_min) { if (alarm_sec == -1) { alarm_sec = cur_sec + 1; } else { if (cur_sec > alarm_sec) { alarm_hour++; } } if (alarm_sec == SEC_PER_MIN) { /* wrap to next hour, minutes is not in don't care mode */ alarm_sec = 0; alarm_hour++; } } else if (cur_min > alarm_min) { alarm_hour++; } } else if (cur_hour == alarm_hour) { if (alarm_min == -1) { alarm_min = cur_min; if (alarm_sec == -1) { alarm_sec = cur_sec + 1; } else if (cur_sec > alarm_sec) { alarm_min++; } if (alarm_sec == SEC_PER_MIN) { alarm_sec = 0; alarm_min++; } /* wrap to next day, hour is not in don't care mode */ alarm_min %= MIN_PER_HOUR; } else if (cur_min == alarm_min) { if (alarm_sec == -1) { alarm_sec = cur_sec + 1; } /* wrap to next day, hours+minutes not in don't care mode */ alarm_sec %= SEC_PER_MIN; } } /* values that are still don't care fire at the next min/sec */ if (alarm_min == -1) { alarm_min = 0; } if (alarm_sec == -1) { alarm_sec = 0; } /* keep values in range */ if (alarm_sec == SEC_PER_MIN) { alarm_sec = 0; alarm_min++; } if (alarm_min == MIN_PER_HOUR) { alarm_min = 0; alarm_hour++; } alarm_hour %= HOUR_PER_DAY; hour = alarm_hour - cur_hour; min = hour * MIN_PER_HOUR + alarm_min - cur_min; sec = min * SEC_PER_MIN + alarm_sec - cur_sec; return sec <= 0 ? sec + SEC_PER_DAY : sec; }