[PATCH v3 6/7] RTC:Add alarm support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add the alarm check when update cycle ended. If alarm is fired,
also AIE bit is setting, then raise a interrupt

Signed-off-by: Yang Zhang <yang.z.zhang@xxxxxxxxx>
---
 hw/mc146818rtc.c |   48 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index fae049e..384bdc1 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -114,6 +114,7 @@ typedef struct RTCState {
 static void rtc_set_time(RTCState *s);
 static void rtc_calibrate_time(RTCState *s);
 static void rtc_set_cmos(RTCState *s);
+static inline int rtc_from_bcd(RTCState *s, int a);

 static int32_t divider_reset;

@@ -267,15 +268,58 @@ static void rtc_update_timer(void *opaque)
     }
 }

+static inline uint8_t convert_hour(RTCState *s, uint8_t hour)
+{
+    if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) {
+        hour %= 12;
+        if (s->cmos_data[RTC_HOURS] & 0x80) {
+            hour += 12;
+        }
+    }
+    return hour;
+}
+static uint32_t check_alarm(RTCState *s)
+{
+    uint8_t alarm_hour, alarm_min, alarm_sec;
+    uint8_t cur_hour, cur_min, cur_sec;
+
+    rtc_calibrate_time(s);
+    rtc_set_cmos(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 = 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_sec & 0xc0) == 0xc0 || alarm_sec == cur_sec) &&
+            ((alarm_min & 0xc0) == 0xc0 || alarm_min == cur_min) &&
+            ((alarm_hour & 0xc0) == 0xc0 || alarm_hour == cur_hour)) {
+        return 1;
+    }
+    return 0;
+
+}
+
 static void rtc_update_timer2(void *opaque)
 {
     RTCState *s = opaque;

     if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
         s->cmos_data[RTC_REG_C] |= REG_C_UF;
+        if (check_alarm(s)) {
+            s->cmos_data[RTC_REG_C] |= REG_C_AF;
+        }
+
         s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
-        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
-        qemu_irq_raise(s->irq);
+        if (s->cmos_data[RTC_REG_B] & (REG_B_AIE | REG_B_UIE)) {
+            s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+            qemu_irq_raise(s->irq);
+        }
     }
     check_update_timer(s);
 }
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux