symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/mc146818rtc.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU MC146818 RTC emulation
       
     3  *
       
     4  * Copyright (c) 2003-2004 Fabrice Bellard
       
     5  *
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     7  * of this software and associated documentation files (the "Software"), to deal
       
     8  * in the Software without restriction, including without limitation the rights
       
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  * copies of the Software, and to permit persons to whom the Software is
       
    11  * furnished to do so, subject to the following conditions:
       
    12  *
       
    13  * The above copyright notice and this permission notice shall be included in
       
    14  * all copies or substantial portions of the Software.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    22  * THE SOFTWARE.
       
    23  */
       
    24 #include "hw.h"
       
    25 #include "qemu-timer.h"
       
    26 #include "sysemu.h"
       
    27 #include "pc.h"
       
    28 #include "isa.h"
       
    29 #include "hpet_emul.h"
       
    30 
       
    31 //#define DEBUG_CMOS
       
    32 
       
    33 #define RTC_SECONDS             0
       
    34 #define RTC_SECONDS_ALARM       1
       
    35 #define RTC_MINUTES             2
       
    36 #define RTC_MINUTES_ALARM       3
       
    37 #define RTC_HOURS               4
       
    38 #define RTC_HOURS_ALARM         5
       
    39 #define RTC_ALARM_DONT_CARE    0xC0
       
    40 
       
    41 #define RTC_DAY_OF_WEEK         6
       
    42 #define RTC_DAY_OF_MONTH        7
       
    43 #define RTC_MONTH               8
       
    44 #define RTC_YEAR                9
       
    45 
       
    46 #define RTC_REG_A               10
       
    47 #define RTC_REG_B               11
       
    48 #define RTC_REG_C               12
       
    49 #define RTC_REG_D               13
       
    50 
       
    51 #define REG_A_UIP 0x80
       
    52 
       
    53 #define REG_B_SET 0x80
       
    54 #define REG_B_PIE 0x40
       
    55 #define REG_B_AIE 0x20
       
    56 #define REG_B_UIE 0x10
       
    57 
       
    58 struct RTCState {
       
    59     uint8_t cmos_data[128];
       
    60     uint8_t cmos_index;
       
    61     struct tm current_tm;
       
    62     qemu_irq irq;
       
    63     int it_shift;
       
    64     /* periodic timer */
       
    65     QEMUTimer *periodic_timer;
       
    66     int64_t next_periodic_time;
       
    67     /* second update */
       
    68     int64_t next_second_time;
       
    69     QEMUTimer *second_timer;
       
    70     QEMUTimer *second_timer2;
       
    71 };
       
    72 
       
    73 static void rtc_irq_raise(qemu_irq irq) {
       
    74     /* When HPET is operating in legacy mode, RTC interrupts are disabled
       
    75      * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
       
    76      * mode is established while interrupt is raised. We want it to
       
    77      * be lowered in any case
       
    78      */
       
    79 #if defined TARGET_I386 || defined TARGET_X86_64
       
    80     if (!hpet_in_legacy_mode())
       
    81 #endif
       
    82         qemu_irq_raise(irq);
       
    83 }
       
    84 
       
    85 static void rtc_set_time(RTCState *s);
       
    86 static void rtc_copy_date(RTCState *s);
       
    87 
       
    88 static void rtc_timer_update(RTCState *s, int64_t current_time)
       
    89 {
       
    90     int period_code, period;
       
    91     int64_t cur_clock, next_irq_clock;
       
    92 
       
    93     period_code = s->cmos_data[RTC_REG_A] & 0x0f;
       
    94 #if defined TARGET_I386 || defined TARGET_X86_64
       
    95     /* disable periodic timer if hpet is in legacy mode, since interrupts are
       
    96      * disabled anyway.
       
    97      */
       
    98     if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) {
       
    99 #else
       
   100     if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
       
   101 #endif
       
   102         if (period_code <= 2)
       
   103             period_code += 7;
       
   104         /* period in 32 Khz cycles */
       
   105         period = 1 << (period_code - 1);
       
   106         /* compute 32 khz clock */
       
   107         cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
       
   108         next_irq_clock = (cur_clock & ~(period - 1)) + period;
       
   109         s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
       
   110         qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
       
   111     } else {
       
   112         qemu_del_timer(s->periodic_timer);
       
   113     }
       
   114 }
       
   115 
       
   116 static void rtc_periodic_timer(void *opaque)
       
   117 {
       
   118     RTCState *s = opaque;
       
   119 
       
   120     rtc_timer_update(s, s->next_periodic_time);
       
   121     s->cmos_data[RTC_REG_C] |= 0xc0;
       
   122     rtc_irq_raise(s->irq);
       
   123 }
       
   124 
       
   125 static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
       
   126 {
       
   127     RTCState *s = opaque;
       
   128 
       
   129     if ((addr & 1) == 0) {
       
   130         s->cmos_index = data & 0x7f;
       
   131     } else {
       
   132 #ifdef DEBUG_CMOS
       
   133         printf("cmos: write index=0x%02x val=0x%02x\n",
       
   134                s->cmos_index, data);
       
   135 #endif
       
   136         switch(s->cmos_index) {
       
   137         case RTC_SECONDS_ALARM:
       
   138         case RTC_MINUTES_ALARM:
       
   139         case RTC_HOURS_ALARM:
       
   140             /* XXX: not supported */
       
   141             s->cmos_data[s->cmos_index] = data;
       
   142             break;
       
   143         case RTC_SECONDS:
       
   144         case RTC_MINUTES:
       
   145         case RTC_HOURS:
       
   146         case RTC_DAY_OF_WEEK:
       
   147         case RTC_DAY_OF_MONTH:
       
   148         case RTC_MONTH:
       
   149         case RTC_YEAR:
       
   150             s->cmos_data[s->cmos_index] = data;
       
   151             /* if in set mode, do not update the time */
       
   152             if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
       
   153                 rtc_set_time(s);
       
   154             }
       
   155             break;
       
   156         case RTC_REG_A:
       
   157             /* UIP bit is read only */
       
   158             s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
       
   159                 (s->cmos_data[RTC_REG_A] & REG_A_UIP);
       
   160             rtc_timer_update(s, qemu_get_clock(vm_clock));
       
   161             break;
       
   162         case RTC_REG_B:
       
   163             if (data & REG_B_SET) {
       
   164                 /* set mode: reset UIP mode */
       
   165                 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
       
   166                 data &= ~REG_B_UIE;
       
   167             } else {
       
   168                 /* if disabling set mode, update the time */
       
   169                 if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
       
   170                     rtc_set_time(s);
       
   171                 }
       
   172             }
       
   173             s->cmos_data[RTC_REG_B] = data;
       
   174             rtc_timer_update(s, qemu_get_clock(vm_clock));
       
   175             break;
       
   176         case RTC_REG_C:
       
   177         case RTC_REG_D:
       
   178             /* cannot write to them */
       
   179             break;
       
   180         default:
       
   181             s->cmos_data[s->cmos_index] = data;
       
   182             break;
       
   183         }
       
   184     }
       
   185 }
       
   186 
       
   187 static inline int to_bcd(RTCState *s, int a)
       
   188 {
       
   189     if (s->cmos_data[RTC_REG_B] & 0x04) {
       
   190         return a;
       
   191     } else {
       
   192         return ((a / 10) << 4) | (a % 10);
       
   193     }
       
   194 }
       
   195 
       
   196 static inline int from_bcd(RTCState *s, int a)
       
   197 {
       
   198     if (s->cmos_data[RTC_REG_B] & 0x04) {
       
   199         return a;
       
   200     } else {
       
   201         return ((a >> 4) * 10) + (a & 0x0f);
       
   202     }
       
   203 }
       
   204 
       
   205 static void rtc_set_time(RTCState *s)
       
   206 {
       
   207     struct tm *tm = &s->current_tm;
       
   208 
       
   209     tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
       
   210     tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
       
   211     tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
       
   212     if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
       
   213         (s->cmos_data[RTC_HOURS] & 0x80)) {
       
   214         tm->tm_hour += 12;
       
   215     }
       
   216     tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
       
   217     tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
       
   218     tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
       
   219     tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
       
   220 }
       
   221 
       
   222 static void rtc_copy_date(RTCState *s)
       
   223 {
       
   224     const struct tm *tm = &s->current_tm;
       
   225 
       
   226     s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
       
   227     s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
       
   228     if (s->cmos_data[RTC_REG_B] & 0x02) {
       
   229         /* 24 hour format */
       
   230         s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
       
   231     } else {
       
   232         /* 12 hour format */
       
   233         s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
       
   234         if (tm->tm_hour >= 12)
       
   235             s->cmos_data[RTC_HOURS] |= 0x80;
       
   236     }
       
   237     s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
       
   238     s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
       
   239     s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
       
   240     s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
       
   241 }
       
   242 
       
   243 /* month is between 0 and 11. */
       
   244 static int get_days_in_month(int month, int year)
       
   245 {
       
   246     static const int days_tab[12] = {
       
   247         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
       
   248     };
       
   249     int d;
       
   250     if ((unsigned )month >= 12)
       
   251         return 31;
       
   252     d = days_tab[month];
       
   253     if (month == 1) {
       
   254         if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
       
   255             d++;
       
   256     }
       
   257     return d;
       
   258 }
       
   259 
       
   260 /* update 'tm' to the next second */
       
   261 static void rtc_next_second(struct tm *tm)
       
   262 {
       
   263     int days_in_month;
       
   264 
       
   265     tm->tm_sec++;
       
   266     if ((unsigned)tm->tm_sec >= 60) {
       
   267         tm->tm_sec = 0;
       
   268         tm->tm_min++;
       
   269         if ((unsigned)tm->tm_min >= 60) {
       
   270             tm->tm_min = 0;
       
   271             tm->tm_hour++;
       
   272             if ((unsigned)tm->tm_hour >= 24) {
       
   273                 tm->tm_hour = 0;
       
   274                 /* next day */
       
   275                 tm->tm_wday++;
       
   276                 if ((unsigned)tm->tm_wday >= 7)
       
   277                     tm->tm_wday = 0;
       
   278                 days_in_month = get_days_in_month(tm->tm_mon,
       
   279                                                   tm->tm_year + 1900);
       
   280                 tm->tm_mday++;
       
   281                 if (tm->tm_mday < 1) {
       
   282                     tm->tm_mday = 1;
       
   283                 } else if (tm->tm_mday > days_in_month) {
       
   284                     tm->tm_mday = 1;
       
   285                     tm->tm_mon++;
       
   286                     if (tm->tm_mon >= 12) {
       
   287                         tm->tm_mon = 0;
       
   288                         tm->tm_year++;
       
   289                     }
       
   290                 }
       
   291             }
       
   292         }
       
   293     }
       
   294 }
       
   295 
       
   296 
       
   297 static void rtc_update_second(void *opaque)
       
   298 {
       
   299     RTCState *s = opaque;
       
   300     int64_t delay;
       
   301 
       
   302     /* if the oscillator is not in normal operation, we do not update */
       
   303     if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
       
   304         s->next_second_time += ticks_per_sec;
       
   305         qemu_mod_timer(s->second_timer, s->next_second_time);
       
   306     } else {
       
   307         rtc_next_second(&s->current_tm);
       
   308 
       
   309         if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
       
   310             /* update in progress bit */
       
   311             s->cmos_data[RTC_REG_A] |= REG_A_UIP;
       
   312         }
       
   313         /* should be 244 us = 8 / 32768 seconds, but currently the
       
   314            timers do not have the necessary resolution. */
       
   315         delay = (ticks_per_sec * 1) / 100;
       
   316         if (delay < 1)
       
   317             delay = 1;
       
   318         qemu_mod_timer(s->second_timer2,
       
   319                        s->next_second_time + delay);
       
   320     }
       
   321 }
       
   322 
       
   323 static void rtc_update_second2(void *opaque)
       
   324 {
       
   325     RTCState *s = opaque;
       
   326 
       
   327     if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
       
   328         rtc_copy_date(s);
       
   329     }
       
   330 
       
   331     /* check alarm */
       
   332     if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
       
   333         if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
       
   334              s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
       
   335             ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
       
   336              s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
       
   337             ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
       
   338              s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
       
   339 
       
   340             s->cmos_data[RTC_REG_C] |= 0xa0;
       
   341             rtc_irq_raise(s->irq);
       
   342         }
       
   343     }
       
   344 
       
   345     /* update ended interrupt */
       
   346     if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
       
   347         s->cmos_data[RTC_REG_C] |= 0x90;
       
   348         rtc_irq_raise(s->irq);
       
   349     }
       
   350 
       
   351     /* clear update in progress bit */
       
   352     s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
       
   353 
       
   354     s->next_second_time += ticks_per_sec;
       
   355     qemu_mod_timer(s->second_timer, s->next_second_time);
       
   356 }
       
   357 
       
   358 static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
       
   359 {
       
   360     RTCState *s = opaque;
       
   361     int ret;
       
   362     if ((addr & 1) == 0) {
       
   363         return 0xff;
       
   364     } else {
       
   365         switch(s->cmos_index) {
       
   366         case RTC_SECONDS:
       
   367         case RTC_MINUTES:
       
   368         case RTC_HOURS:
       
   369         case RTC_DAY_OF_WEEK:
       
   370         case RTC_DAY_OF_MONTH:
       
   371         case RTC_MONTH:
       
   372         case RTC_YEAR:
       
   373             ret = s->cmos_data[s->cmos_index];
       
   374             break;
       
   375         case RTC_REG_A:
       
   376             ret = s->cmos_data[s->cmos_index];
       
   377             break;
       
   378         case RTC_REG_C:
       
   379             ret = s->cmos_data[s->cmos_index];
       
   380             qemu_irq_lower(s->irq);
       
   381             s->cmos_data[RTC_REG_C] = 0x00;
       
   382             break;
       
   383         default:
       
   384             ret = s->cmos_data[s->cmos_index];
       
   385             break;
       
   386         }
       
   387 #ifdef DEBUG_CMOS
       
   388         printf("cmos: read index=0x%02x val=0x%02x\n",
       
   389                s->cmos_index, ret);
       
   390 #endif
       
   391         return ret;
       
   392     }
       
   393 }
       
   394 
       
   395 void rtc_set_memory(RTCState *s, int addr, int val)
       
   396 {
       
   397     if (addr >= 0 && addr <= 127)
       
   398         s->cmos_data[addr] = val;
       
   399 }
       
   400 
       
   401 void rtc_set_date(RTCState *s, const struct tm *tm)
       
   402 {
       
   403     s->current_tm = *tm;
       
   404     rtc_copy_date(s);
       
   405 }
       
   406 
       
   407 /* PC cmos mappings */
       
   408 #define REG_IBM_CENTURY_BYTE        0x32
       
   409 #define REG_IBM_PS2_CENTURY_BYTE    0x37
       
   410 
       
   411 static void rtc_set_date_from_host(RTCState *s)
       
   412 {
       
   413     struct tm tm;
       
   414     int val;
       
   415 
       
   416     /* set the CMOS date */
       
   417     qemu_get_timedate(&tm, 0);
       
   418     rtc_set_date(s, &tm);
       
   419 
       
   420     val = to_bcd(s, (tm.tm_year / 100) + 19);
       
   421     rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
       
   422     rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
       
   423 }
       
   424 
       
   425 static void rtc_save(QEMUFile *f, void *opaque)
       
   426 {
       
   427     RTCState *s = opaque;
       
   428 
       
   429     qemu_put_buffer(f, s->cmos_data, 128);
       
   430     qemu_put_8s(f, &s->cmos_index);
       
   431 
       
   432     qemu_put_be32(f, s->current_tm.tm_sec);
       
   433     qemu_put_be32(f, s->current_tm.tm_min);
       
   434     qemu_put_be32(f, s->current_tm.tm_hour);
       
   435     qemu_put_be32(f, s->current_tm.tm_wday);
       
   436     qemu_put_be32(f, s->current_tm.tm_mday);
       
   437     qemu_put_be32(f, s->current_tm.tm_mon);
       
   438     qemu_put_be32(f, s->current_tm.tm_year);
       
   439 
       
   440     qemu_put_timer(f, s->periodic_timer);
       
   441     qemu_put_be64(f, s->next_periodic_time);
       
   442 
       
   443     qemu_put_be64(f, s->next_second_time);
       
   444     qemu_put_timer(f, s->second_timer);
       
   445     qemu_put_timer(f, s->second_timer2);
       
   446 }
       
   447 
       
   448 static int rtc_load(QEMUFile *f, void *opaque, int version_id)
       
   449 {
       
   450     RTCState *s = opaque;
       
   451 
       
   452     if (version_id != 1)
       
   453         return -EINVAL;
       
   454 
       
   455     qemu_get_buffer(f, s->cmos_data, 128);
       
   456     qemu_get_8s(f, &s->cmos_index);
       
   457 
       
   458     s->current_tm.tm_sec=qemu_get_be32(f);
       
   459     s->current_tm.tm_min=qemu_get_be32(f);
       
   460     s->current_tm.tm_hour=qemu_get_be32(f);
       
   461     s->current_tm.tm_wday=qemu_get_be32(f);
       
   462     s->current_tm.tm_mday=qemu_get_be32(f);
       
   463     s->current_tm.tm_mon=qemu_get_be32(f);
       
   464     s->current_tm.tm_year=qemu_get_be32(f);
       
   465 
       
   466     qemu_get_timer(f, s->periodic_timer);
       
   467     s->next_periodic_time=qemu_get_be64(f);
       
   468 
       
   469     s->next_second_time=qemu_get_be64(f);
       
   470     qemu_get_timer(f, s->second_timer);
       
   471     qemu_get_timer(f, s->second_timer2);
       
   472     return 0;
       
   473 }
       
   474 
       
   475 RTCState *rtc_init(int base, qemu_irq irq)
       
   476 {
       
   477     RTCState *s;
       
   478 
       
   479     s = qemu_mallocz(sizeof(RTCState));
       
   480     if (!s)
       
   481         return NULL;
       
   482 
       
   483     s->irq = irq;
       
   484     s->cmos_data[RTC_REG_A] = 0x26;
       
   485     s->cmos_data[RTC_REG_B] = 0x02;
       
   486     s->cmos_data[RTC_REG_C] = 0x00;
       
   487     s->cmos_data[RTC_REG_D] = 0x80;
       
   488 
       
   489     rtc_set_date_from_host(s);
       
   490 
       
   491     s->periodic_timer = qemu_new_timer(vm_clock,
       
   492                                        rtc_periodic_timer, s);
       
   493     s->second_timer = qemu_new_timer(vm_clock,
       
   494                                      rtc_update_second, s);
       
   495     s->second_timer2 = qemu_new_timer(vm_clock,
       
   496                                       rtc_update_second2, s);
       
   497 
       
   498     s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
       
   499     qemu_mod_timer(s->second_timer2, s->next_second_time);
       
   500 
       
   501     register_ioport_write(base, 2, 1, cmos_ioport_write, s);
       
   502     register_ioport_read(base, 2, 1, cmos_ioport_read, s);
       
   503 
       
   504     register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
       
   505     return s;
       
   506 }
       
   507 
       
   508 /* Memory mapped interface */
       
   509 static uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
       
   510 {
       
   511     RTCState *s = opaque;
       
   512 
       
   513     return cmos_ioport_read(s, addr >> s->it_shift) & 0xFF;
       
   514 }
       
   515 
       
   516 static void cmos_mm_writeb (void *opaque,
       
   517                             target_phys_addr_t addr, uint32_t value)
       
   518 {
       
   519     RTCState *s = opaque;
       
   520 
       
   521     cmos_ioport_write(s, addr >> s->it_shift, value & 0xFF);
       
   522 }
       
   523 
       
   524 static uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
       
   525 {
       
   526     RTCState *s = opaque;
       
   527     uint32_t val;
       
   528 
       
   529     val = cmos_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
       
   530 #ifdef TARGET_WORDS_BIGENDIAN
       
   531     val = bswap16(val);
       
   532 #endif
       
   533     return val;
       
   534 }
       
   535 
       
   536 static void cmos_mm_writew (void *opaque,
       
   537                             target_phys_addr_t addr, uint32_t value)
       
   538 {
       
   539     RTCState *s = opaque;
       
   540 #ifdef TARGET_WORDS_BIGENDIAN
       
   541     value = bswap16(value);
       
   542 #endif
       
   543     cmos_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
       
   544 }
       
   545 
       
   546 static uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
       
   547 {
       
   548     RTCState *s = opaque;
       
   549     uint32_t val;
       
   550 
       
   551     val = cmos_ioport_read(s, addr >> s->it_shift);
       
   552 #ifdef TARGET_WORDS_BIGENDIAN
       
   553     val = bswap32(val);
       
   554 #endif
       
   555     return val;
       
   556 }
       
   557 
       
   558 static void cmos_mm_writel (void *opaque,
       
   559                             target_phys_addr_t addr, uint32_t value)
       
   560 {
       
   561     RTCState *s = opaque;
       
   562 #ifdef TARGET_WORDS_BIGENDIAN
       
   563     value = bswap32(value);
       
   564 #endif
       
   565     cmos_ioport_write(s, addr >> s->it_shift, value);
       
   566 }
       
   567 
       
   568 static CPUReadMemoryFunc *rtc_mm_read[] = {
       
   569     &cmos_mm_readb,
       
   570     &cmos_mm_readw,
       
   571     &cmos_mm_readl,
       
   572 };
       
   573 
       
   574 static CPUWriteMemoryFunc *rtc_mm_write[] = {
       
   575     &cmos_mm_writeb,
       
   576     &cmos_mm_writew,
       
   577     &cmos_mm_writel,
       
   578 };
       
   579 
       
   580 RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)
       
   581 {
       
   582     RTCState *s;
       
   583     int io_memory;
       
   584 
       
   585     s = qemu_mallocz(sizeof(RTCState));
       
   586     if (!s)
       
   587         return NULL;
       
   588 
       
   589     s->irq = irq;
       
   590     s->cmos_data[RTC_REG_A] = 0x26;
       
   591     s->cmos_data[RTC_REG_B] = 0x02;
       
   592     s->cmos_data[RTC_REG_C] = 0x00;
       
   593     s->cmos_data[RTC_REG_D] = 0x80;
       
   594 
       
   595     rtc_set_date_from_host(s);
       
   596 
       
   597     s->periodic_timer = qemu_new_timer(vm_clock,
       
   598                                        rtc_periodic_timer, s);
       
   599     s->second_timer = qemu_new_timer(vm_clock,
       
   600                                      rtc_update_second, s);
       
   601     s->second_timer2 = qemu_new_timer(vm_clock,
       
   602                                       rtc_update_second2, s);
       
   603 
       
   604     s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
       
   605     qemu_mod_timer(s->second_timer2, s->next_second_time);
       
   606 
       
   607     io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s);
       
   608     cpu_register_physical_memory(base, 2 << it_shift, io_memory);
       
   609 
       
   610     register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
       
   611     return s;
       
   612 }