qemu/hw/mc146818rtc.c
<<
>>
Prefs
   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 "apic.h"
  29#include "isa.h"
  30#include "mc146818rtc.h"
  31
  32//#define DEBUG_CMOS
  33//#define DEBUG_COALESCED
  34
  35#ifdef DEBUG_CMOS
  36# define CMOS_DPRINTF(format, ...)      printf(format, ## __VA_ARGS__)
  37#else
  38# define CMOS_DPRINTF(format, ...)      do { } while (0)
  39#endif
  40
  41#ifdef DEBUG_COALESCED
  42# define DPRINTF_C(format, ...)      printf(format, ## __VA_ARGS__)
  43#else
  44# define DPRINTF_C(format, ...)      do { } while (0)
  45#endif
  46
  47#define RTC_REINJECT_ON_ACK_COUNT 20
  48
  49#define RTC_SECONDS             0
  50#define RTC_SECONDS_ALARM       1
  51#define RTC_MINUTES             2
  52#define RTC_MINUTES_ALARM       3
  53#define RTC_HOURS               4
  54#define RTC_HOURS_ALARM         5
  55#define RTC_ALARM_DONT_CARE    0xC0
  56
  57#define RTC_DAY_OF_WEEK         6
  58#define RTC_DAY_OF_MONTH        7
  59#define RTC_MONTH               8
  60#define RTC_YEAR                9
  61
  62#define RTC_REG_A               10
  63#define RTC_REG_B               11
  64#define RTC_REG_C               12
  65#define RTC_REG_D               13
  66
  67#define REG_A_UIP 0x80
  68
  69#define REG_B_SET  0x80
  70#define REG_B_PIE  0x40
  71#define REG_B_AIE  0x20
  72#define REG_B_UIE  0x10
  73#define REG_B_SQWE 0x08
  74#define REG_B_DM   0x04
  75
  76#define REG_C_UF   0x10
  77#define REG_C_IRQF 0x80
  78#define REG_C_PF   0x40
  79#define REG_C_AF   0x20
  80
  81typedef struct RTCState {
  82    ISADevice dev;
  83    uint8_t cmos_data[128];
  84    uint8_t cmos_index;
  85    struct tm current_tm;
  86    int32_t base_year;
  87    qemu_irq irq;
  88    qemu_irq sqw_irq;
  89    int it_shift;
  90    /* periodic timer */
  91    QEMUTimer *periodic_timer;
  92    int64_t next_periodic_time;
  93    /* second update */
  94    int64_t next_second_time;
  95    uint16_t irq_reinject_on_ack_count;
  96    uint32_t irq_coalesced;
  97    uint32_t period;
  98    QEMUTimer *coalesced_timer;
  99    QEMUTimer *second_timer;
 100    QEMUTimer *second_timer2;
 101} RTCState;
 102
 103static void rtc_set_time(RTCState *s);
 104static void rtc_copy_date(RTCState *s);
 105
 106#ifdef TARGET_I386
 107static void rtc_coalesced_timer_update(RTCState *s)
 108{
 109    if (s->irq_coalesced == 0) {
 110        qemu_del_timer(s->coalesced_timer);
 111    } else {
 112        /* divide each RTC interval to 2 - 8 smaller intervals */
 113        int c = MIN(s->irq_coalesced, 7) + 1; 
 114        int64_t next_clock = qemu_get_clock(rtc_clock) +
 115            muldiv64(s->period / c, get_ticks_per_sec(), 32768);
 116        qemu_mod_timer(s->coalesced_timer, next_clock);
 117    }
 118}
 119
 120static void rtc_coalesced_timer(void *opaque)
 121{
 122    RTCState *s = opaque;
 123
 124    if (s->irq_coalesced != 0) {
 125        apic_reset_irq_delivered();
 126        s->cmos_data[RTC_REG_C] |= 0xc0;
 127        DPRINTF_C("cmos: injecting from timer\n");
 128        qemu_irq_raise(s->irq);
 129        if (apic_get_irq_delivered()) {
 130            s->irq_coalesced--;
 131            DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
 132                      s->irq_coalesced);
 133        }
 134    }
 135
 136    rtc_coalesced_timer_update(s);
 137}
 138#endif
 139
 140static void rtc_timer_update(RTCState *s, int64_t current_time)
 141{
 142    int period_code, period;
 143    int64_t cur_clock, next_irq_clock;
 144
 145    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
 146    if (period_code != 0
 147        && ((s->cmos_data[RTC_REG_B] & REG_B_PIE)
 148            || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
 149        if (period_code <= 2)
 150            period_code += 7;
 151        /* period in 32 Khz cycles */
 152        period = 1 << (period_code - 1);
 153#ifdef TARGET_I386
 154        if (period != s->period) {
 155            s->irq_coalesced = (s->irq_coalesced * s->period) / period;
 156            DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced);
 157        }
 158        s->period = period;
 159#endif
 160        /* compute 32 khz clock */
 161        cur_clock = muldiv64(current_time, 32768, get_ticks_per_sec());
 162        next_irq_clock = (cur_clock & ~(period - 1)) + period;
 163        s->next_periodic_time =
 164            muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1;
 165        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
 166    } else {
 167#ifdef TARGET_I386
 168        s->irq_coalesced = 0;
 169#endif
 170        qemu_del_timer(s->periodic_timer);
 171    }
 172}
 173
 174static void rtc_periodic_timer(void *opaque)
 175{
 176    RTCState *s = opaque;
 177
 178    rtc_timer_update(s, s->next_periodic_time);
 179    if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
 180        s->cmos_data[RTC_REG_C] |= 0xc0;
 181#ifdef TARGET_I386
 182        if(rtc_td_hack) {
 183            if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
 184                s->irq_reinject_on_ack_count = 0;               
 185            apic_reset_irq_delivered();
 186            qemu_irq_raise(s->irq);
 187            if (!apic_get_irq_delivered()) {
 188                s->irq_coalesced++;
 189                rtc_coalesced_timer_update(s);
 190                DPRINTF_C("cmos: coalesced irqs increased to %d\n",
 191                          s->irq_coalesced);
 192            }
 193        } else
 194#endif
 195        qemu_irq_raise(s->irq);
 196    }
 197    if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
 198        /* Not square wave at all but we don't want 2048Hz interrupts!
 199           Must be seen as a pulse.  */
 200        qemu_irq_raise(s->sqw_irq);
 201    }
 202}
 203
 204static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
 205{
 206    RTCState *s = opaque;
 207
 208    if ((addr & 1) == 0) {
 209        s->cmos_index = data & 0x7f;
 210    } else {
 211        CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n",
 212                     s->cmos_index, data);
 213        switch(s->cmos_index) {
 214        case RTC_SECONDS_ALARM:
 215        case RTC_MINUTES_ALARM:
 216        case RTC_HOURS_ALARM:
 217            s->cmos_data[s->cmos_index] = data;
 218            break;
 219        case RTC_SECONDS:
 220        case RTC_MINUTES:
 221        case RTC_HOURS:
 222        case RTC_DAY_OF_WEEK:
 223        case RTC_DAY_OF_MONTH:
 224        case RTC_MONTH:
 225        case RTC_YEAR:
 226            s->cmos_data[s->cmos_index] = data;
 227            /* if in set mode, do not update the time */
 228            if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
 229                rtc_set_time(s);
 230            }
 231            break;
 232        case RTC_REG_A:
 233            /* UIP bit is read only */
 234            s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
 235                (s->cmos_data[RTC_REG_A] & REG_A_UIP);
 236            rtc_timer_update(s, qemu_get_clock(rtc_clock));
 237            break;
 238        case RTC_REG_B:
 239            if (data & REG_B_SET) {
 240                /* set mode: reset UIP mode */
 241                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
 242                data &= ~REG_B_UIE;
 243            } else {
 244                /* if disabling set mode, update the time */
 245                if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
 246                    rtc_set_time(s);
 247                }
 248            }
 249            s->cmos_data[RTC_REG_B] = data;
 250            rtc_timer_update(s, qemu_get_clock(rtc_clock));
 251            break;
 252        case RTC_REG_C:
 253        case RTC_REG_D:
 254            /* cannot write to them */
 255            break;
 256        default:
 257            s->cmos_data[s->cmos_index] = data;
 258            break;
 259        }
 260    }
 261}
 262
 263static inline int rtc_to_bcd(RTCState *s, int a)
 264{
 265    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
 266        return a;
 267    } else {
 268        return ((a / 10) << 4) | (a % 10);
 269    }
 270}
 271
 272static inline int rtc_from_bcd(RTCState *s, int a)
 273{
 274    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
 275        return a;
 276    } else {
 277        return ((a >> 4) * 10) + (a & 0x0f);
 278    }
 279}
 280
 281static void rtc_set_time(RTCState *s)
 282{
 283    struct tm *tm = &s->current_tm;
 284
 285    tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
 286    tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
 287    tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
 288    if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
 289        (s->cmos_data[RTC_HOURS] & 0x80)) {
 290        tm->tm_hour += 12;
 291    }
 292    tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
 293    tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
 294    tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
 295    tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
 296
 297    rtc_change_mon_event(tm);
 298}
 299
 300static void rtc_copy_date(RTCState *s)
 301{
 302    const struct tm *tm = &s->current_tm;
 303    int year;
 304
 305    s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
 306    s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
 307    if (s->cmos_data[RTC_REG_B] & 0x02) {
 308        /* 24 hour format */
 309        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
 310    } else {
 311        /* 12 hour format */
 312        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour % 12);
 313        if (tm->tm_hour >= 12)
 314            s->cmos_data[RTC_HOURS] |= 0x80;
 315    }
 316    s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1);
 317    s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
 318    s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
 319    year = (tm->tm_year - s->base_year) % 100;
 320    if (year < 0)
 321        year += 100;
 322    s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year);
 323}
 324
 325/* month is between 0 and 11. */
 326static int get_days_in_month(int month, int year)
 327{
 328    static const int days_tab[12] = {
 329        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 330    };
 331    int d;
 332    if ((unsigned )month >= 12)
 333        return 31;
 334    d = days_tab[month];
 335    if (month == 1) {
 336        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
 337            d++;
 338    }
 339    return d;
 340}
 341
 342/* update 'tm' to the next second */
 343static void rtc_next_second(struct tm *tm)
 344{
 345    int days_in_month;
 346
 347    tm->tm_sec++;
 348    if ((unsigned)tm->tm_sec >= 60) {
 349        tm->tm_sec = 0;
 350        tm->tm_min++;
 351        if ((unsigned)tm->tm_min >= 60) {
 352            tm->tm_min = 0;
 353            tm->tm_hour++;
 354            if ((unsigned)tm->tm_hour >= 24) {
 355                tm->tm_hour = 0;
 356                /* next day */
 357                tm->tm_wday++;
 358                if ((unsigned)tm->tm_wday >= 7)
 359                    tm->tm_wday = 0;
 360                days_in_month = get_days_in_month(tm->tm_mon,
 361                                                  tm->tm_year + 1900);
 362                tm->tm_mday++;
 363                if (tm->tm_mday < 1) {
 364                    tm->tm_mday = 1;
 365                } else if (tm->tm_mday > days_in_month) {
 366                    tm->tm_mday = 1;
 367                    tm->tm_mon++;
 368                    if (tm->tm_mon >= 12) {
 369                        tm->tm_mon = 0;
 370                        tm->tm_year++;
 371                    }
 372                }
 373            }
 374        }
 375    }
 376}
 377
 378
 379static void rtc_update_second(void *opaque)
 380{
 381    RTCState *s = opaque;
 382    int64_t delay;
 383
 384    /* if the oscillator is not in normal operation, we do not update */
 385    if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
 386        s->next_second_time += get_ticks_per_sec();
 387        qemu_mod_timer(s->second_timer, s->next_second_time);
 388    } else {
 389        rtc_next_second(&s->current_tm);
 390
 391        if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
 392            /* update in progress bit */
 393            s->cmos_data[RTC_REG_A] |= REG_A_UIP;
 394        }
 395        /* should be 244 us = 8 / 32768 seconds, but currently the
 396           timers do not have the necessary resolution. */
 397        delay = (get_ticks_per_sec() * 1) / 100;
 398        if (delay < 1)
 399            delay = 1;
 400        qemu_mod_timer(s->second_timer2,
 401                       s->next_second_time + delay);
 402    }
 403}
 404
 405static void rtc_update_second2(void *opaque)
 406{
 407    RTCState *s = opaque;
 408
 409    if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
 410        rtc_copy_date(s);
 411    }
 412
 413    /* check alarm */
 414    if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
 415        if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
 416             rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) &&
 417            ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
 418             rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) &&
 419            ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
 420             rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) {
 421
 422            s->cmos_data[RTC_REG_C] |= 0xa0;
 423            qemu_irq_raise(s->irq);
 424        }
 425    }
 426
 427    /* update ended interrupt */
 428    s->cmos_data[RTC_REG_C] |= REG_C_UF;
 429    if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
 430        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
 431        qemu_irq_raise(s->irq);
 432    }
 433
 434    /* clear update in progress bit */
 435    s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
 436
 437    s->next_second_time += get_ticks_per_sec();
 438    qemu_mod_timer(s->second_timer, s->next_second_time);
 439}
 440
 441static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
 442{
 443    RTCState *s = opaque;
 444    int ret;
 445    if ((addr & 1) == 0) {
 446        return 0xff;
 447    } else {
 448        switch(s->cmos_index) {
 449        case RTC_SECONDS:
 450        case RTC_MINUTES:
 451        case RTC_HOURS:
 452        case RTC_DAY_OF_WEEK:
 453        case RTC_DAY_OF_MONTH:
 454        case RTC_MONTH:
 455        case RTC_YEAR:
 456            ret = s->cmos_data[s->cmos_index];
 457            break;
 458        case RTC_REG_A:
 459            ret = s->cmos_data[s->cmos_index];
 460            break;
 461        case RTC_REG_C:
 462            ret = s->cmos_data[s->cmos_index];
 463            qemu_irq_lower(s->irq);
 464#ifdef TARGET_I386
 465            if(s->irq_coalesced &&
 466                    s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) {
 467                s->irq_reinject_on_ack_count++;
 468                apic_reset_irq_delivered();
 469                DPRINTF_C("cmos: injecting on ack\n");
 470                qemu_irq_raise(s->irq);
 471                if (apic_get_irq_delivered()) {
 472                    s->irq_coalesced--;
 473                    DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
 474                              s->irq_coalesced);
 475                }
 476                break;
 477            }
 478#endif
 479
 480            s->cmos_data[RTC_REG_C] = 0x00;
 481            break;
 482        default:
 483            ret = s->cmos_data[s->cmos_index];
 484            break;
 485        }
 486        CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n",
 487                     s->cmos_index, ret);
 488        return ret;
 489    }
 490}
 491
 492void rtc_set_memory(ISADevice *dev, int addr, int val)
 493{
 494    RTCState *s = DO_UPCAST(RTCState, dev, dev);
 495    if (addr >= 0 && addr <= 127)
 496        s->cmos_data[addr] = val;
 497}
 498
 499void rtc_set_date(ISADevice *dev, const struct tm *tm)
 500{
 501    RTCState *s = DO_UPCAST(RTCState, dev, dev);
 502    s->current_tm = *tm;
 503    rtc_copy_date(s);
 504}
 505
 506/* PC cmos mappings */
 507#define REG_IBM_CENTURY_BYTE        0x32
 508#define REG_IBM_PS2_CENTURY_BYTE    0x37
 509
 510static void rtc_set_date_from_host(ISADevice *dev)
 511{
 512    RTCState *s = DO_UPCAST(RTCState, dev, dev);
 513    struct tm tm;
 514    int val;
 515
 516    /* set the CMOS date */
 517    qemu_get_timedate(&tm, 0);
 518    rtc_set_date(dev, &tm);
 519
 520    val = rtc_to_bcd(s, (tm.tm_year / 100) + 19);
 521    rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val);
 522    rtc_set_memory(dev, REG_IBM_PS2_CENTURY_BYTE, val);
 523}
 524
 525static int rtc_post_load(void *opaque, int version_id)
 526{
 527#ifdef TARGET_I386
 528    RTCState *s = opaque;
 529
 530    if (version_id >= 2) {
 531        if (rtc_td_hack) {
 532            rtc_coalesced_timer_update(s);
 533        }
 534    }
 535#endif
 536    return 0;
 537}
 538
 539static const VMStateDescription vmstate_rtc = {
 540    .name = "mc146818rtc",
 541    .version_id = 2,
 542    .minimum_version_id = 1,
 543    .minimum_version_id_old = 1,
 544    .post_load = rtc_post_load,
 545    .fields      = (VMStateField []) {
 546        VMSTATE_BUFFER(cmos_data, RTCState),
 547        VMSTATE_UINT8(cmos_index, RTCState),
 548        VMSTATE_INT32(current_tm.tm_sec, RTCState),
 549        VMSTATE_INT32(current_tm.tm_min, RTCState),
 550        VMSTATE_INT32(current_tm.tm_hour, RTCState),
 551        VMSTATE_INT32(current_tm.tm_wday, RTCState),
 552        VMSTATE_INT32(current_tm.tm_mday, RTCState),
 553        VMSTATE_INT32(current_tm.tm_mon, RTCState),
 554        VMSTATE_INT32(current_tm.tm_year, RTCState),
 555        VMSTATE_TIMER(periodic_timer, RTCState),
 556        VMSTATE_INT64(next_periodic_time, RTCState),
 557        VMSTATE_INT64(next_second_time, RTCState),
 558        VMSTATE_TIMER(second_timer, RTCState),
 559        VMSTATE_TIMER(second_timer2, RTCState),
 560        VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
 561        VMSTATE_UINT32_V(period, RTCState, 2),
 562        VMSTATE_END_OF_LIST()
 563    }
 564};
 565
 566static void rtc_reset(void *opaque)
 567{
 568    RTCState *s = opaque;
 569
 570    s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
 571    s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
 572
 573    qemu_irq_lower(s->irq);
 574
 575#ifdef TARGET_I386
 576    if (rtc_td_hack)
 577            s->irq_coalesced = 0;
 578#endif
 579}
 580
 581static int rtc_initfn(ISADevice *dev)
 582{
 583    RTCState *s = DO_UPCAST(RTCState, dev, dev);
 584    int base = 0x70;
 585
 586    s->cmos_data[RTC_REG_A] = 0x26;
 587    s->cmos_data[RTC_REG_B] = 0x02;
 588    s->cmos_data[RTC_REG_C] = 0x00;
 589    s->cmos_data[RTC_REG_D] = 0x80;
 590
 591    rtc_set_date_from_host(dev);
 592
 593    s->periodic_timer = qemu_new_timer(rtc_clock, rtc_periodic_timer, s);
 594#ifdef TARGET_I386
 595    if (rtc_td_hack)
 596        s->coalesced_timer =
 597            qemu_new_timer(rtc_clock, rtc_coalesced_timer, s);
 598#endif
 599    s->second_timer = qemu_new_timer(rtc_clock, rtc_update_second, s);
 600    s->second_timer2 = qemu_new_timer(rtc_clock, rtc_update_second2, s);
 601
 602    s->next_second_time =
 603        qemu_get_clock(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
 604    qemu_mod_timer(s->second_timer2, s->next_second_time);
 605
 606    register_ioport_write(base, 2, 1, cmos_ioport_write, s);
 607    register_ioport_read(base, 2, 1, cmos_ioport_read, s);
 608
 609    qdev_set_legacy_instance_id(&dev->qdev, base, 2);
 610    qemu_register_reset(rtc_reset, s);
 611    return 0;
 612}
 613
 614ISADevice *rtc_init(int base_year, qemu_irq intercept_irq)
 615{
 616    ISADevice *dev;
 617    RTCState *s;
 618
 619    dev = isa_create("mc146818rtc");
 620    s = DO_UPCAST(RTCState, dev, dev);
 621    qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
 622    qdev_init_nofail(&dev->qdev);
 623    if (intercept_irq) {
 624        s->irq = intercept_irq;
 625    } else {
 626        isa_init_irq(dev, &s->irq, RTC_ISA_IRQ);
 627    }
 628    return dev;
 629}
 630
 631static ISADeviceInfo mc146818rtc_info = {
 632    .qdev.name     = "mc146818rtc",
 633    .qdev.size     = sizeof(RTCState),
 634    .qdev.no_user  = 1,
 635    .qdev.vmsd     = &vmstate_rtc,
 636    .init          = rtc_initfn,
 637    .qdev.props    = (Property[]) {
 638        DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
 639        DEFINE_PROP_END_OF_LIST(),
 640    }
 641};
 642
 643static void mc146818rtc_register(void)
 644{
 645    isa_qdev_register(&mc146818rtc_info);
 646}
 647device_init(mc146818rtc_register)
 648