Patchwork [v3,6/7] RTC:Add alarm support

login
register
mail settings
Submitter Zhang, Yang Z
Date March 2, 2012, 7 a.m.
Message ID <A9667DDFB95DB7438FA9D7D576C3D87E085077@SHSMSX101.ccr.corp.intel.com>
Download mbox | patch
Permalink /patch/144146/
State New
Headers show

Comments

Zhang, Yang Z - March 2, 2012, 7 a.m.
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@Intel.com>
---
 hw/mc146818rtc.c |   48 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 46 insertions(+), 2 deletions(-)

--
1.7.1

Patch

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);
 }