Exemple #1
0
static inline void strongarm_rtc_timer_update(StrongARMRTCState *s)
{
    if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) {
        qemu_mod_timer(s->rtc_hz, s->last_hz + 1000);
    } else {
        qemu_del_timer(s->rtc_hz);
    }

    if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) {
        qemu_mod_timer(s->rtc_alarm, s->last_hz +
                (((s->rtar - s->last_rcnr) * 1000 *
                  ((s->rttr & 0xffff) + 1)) >> 15));
    } else {
Exemple #2
0
/* ACPI PM_TMR */
void acpi_pm_tmr_update(ACPIREGS *ar, bool enable)
{
    int64_t expire_time;

    /* schedule a timer interruption if needed */
    if (enable) {
        expire_time = muldiv64(ar->tmr.overflow_time, get_ticks_per_sec(),
                               PM_TIMER_FREQUENCY);
        qemu_mod_timer(ar->tmr.timer, expire_time);
    } else {
        qemu_del_timer(ar->tmr.timer);
    }
}
Exemple #3
0
/* Set CPU Timer */
void HELPER(spt)(CPUS390XState *env, uint64_t a1)
{
    uint64_t time = cpu_ldq_data(env, a1);

    if (time == -1ULL) {
        return;
    }

    /* nanoseconds */
    time = (time * 125) >> 9;

    qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
}
Exemple #4
0
static void tusb6010_power(TUSBState *s, int on)
{
    if (!on) {
        s->power = 0;
    } else if (!s->power && on) {
        s->power = 1;
        /* Pull the interrupt down after TUSB6010 comes up.  */
        s->intr_ok = 0;
        tusb_intr_update(s);
        qemu_mod_timer(s->pwr_timer,
                       qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2);
    }
}
Exemple #5
0
static int rtc_initfn(ISADevice *dev)
{
    RTCState *s = DO_UPCAST(RTCState, dev, dev);
    int base = 0x70;

    s->cmos_data[RTC_REG_A] = 0x26;
    s->cmos_data[RTC_REG_B] = 0x02;
    s->cmos_data[RTC_REG_C] = 0x00;
    s->cmos_data[RTC_REG_D] = 0x80;

    rtc_set_date_from_host(dev);

#ifdef TARGET_I386
    switch (s->lost_tick_policy) {
    case LOST_TICK_SLEW:
        s->coalesced_timer =
            qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
        break;
    case LOST_TICK_DISCARD:
        break;
    default:
        return -EINVAL;
    }
#endif

    s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
    s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
    s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);

    s->clock_reset_notifier.notify = rtc_notify_clock_reset;
    qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);

    s->suspend_notifier.notify = rtc_notify_suspend;
    qemu_register_suspend_notifier(&s->suspend_notifier);

    s->next_second_time =
        qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
    qemu_mod_timer(s->second_timer2, s->next_second_time);

    memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2);
    isa_register_ioport(dev, &s->io, base);

    qdev_set_legacy_instance_id(&dev->qdev, base, 2);
    qemu_register_reset(rtc_reset, s);

    object_property_add(OBJECT(s), "date", "struct tm",
                        rtc_get_date, NULL, NULL, s, NULL);

    return 0;
}
Exemple #6
0
static void rtc_timer_update(RTCState *s, int64_t current_time)
{
    int period_code, period;
    int64_t cur_clock, next_irq_clock;

    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
#if defined TARGET_I386 || defined TARGET_X86_64
    /* disable periodic timer if hpet is in legacy mode, since interrupts are
     * disabled anyway.
     */
    if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) {
#else
    if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
#endif
        if (period_code <= 2)
            period_code += 7;
        /* period in 32 Khz cycles */
        period = 1 << (period_code - 1);
#ifdef TARGET_I386
        if(period != s->period)
            s->irq_coalesced = (s->irq_coalesced * s->period) / period;
        s->period = period;
#endif
        /* compute 32 khz clock */
        cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
        next_irq_clock = (cur_clock & ~(period - 1)) + period;
        s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
    } else {
#ifdef TARGET_I386
        s->irq_coalesced = 0;
#endif
        qemu_del_timer(s->periodic_timer);
    }
}

static void rtc_periodic_timer(void *opaque)
{
    RTCState *s = opaque;

    rtc_timer_update(s, s->next_periodic_time);
#ifdef TARGET_I386
    if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) {
        s->irq_coalesced++;
        return;
    }
#endif
    s->cmos_data[RTC_REG_C] |= 0xc0;
    rtc_irq_raise(s->irq);
}
Exemple #7
0
void tusb6010_power(struct tusb_s *s, int on)
{
    if (!on)
        s->power = 0;
    else if (!s->power && on) {
        s->power = 1;

        /* Pull the interrupt down after TUSB6010 comes up.  */
        s->intr_ok = 0;
        tusb_intr_update(s);
        qemu_mod_timer(s->pwr_timer,
                        qemu_get_clock(vm_clock) + ticks_per_sec / 2);
    }
}
Exemple #8
0
/* A write to this register enables the timer. */
static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
{
    IB700State *s = vp;
    static int time_map[] = {
        30, 28, 26, 24, 22, 20, 18, 16,
        14, 12, 10,  8,  6,  4,  2,  0
    };
    int64_t timeout;

    ib700_debug("addr = %x, data = %x\n", addr, data);

    timeout = (int64_t) time_map[data & 0xF] * get_ticks_per_sec();
    qemu_mod_timer(s->timer, qemu_get_clock_ns (vm_clock) + timeout);
}
Exemple #9
0
void enqueue_async_event(NVMEState *n, uint8_t event_type, uint8_t event_info,
    uint8_t log_page)
{
    AsyncEvent *event = (AsyncEvent *)qemu_malloc(sizeof(AsyncEvent));

    event->result.event_type = event_type;
    event->result.event_info = event_info;
    event->result.log_page   = log_page;

    QSIMPLEQ_INSERT_TAIL(&(n->async_queue), event, entry);

    qemu_mod_timer(n->async_event_timer,
            qemu_get_clock_ns(vm_clock) + 20000);
}
Exemple #10
0
void qemu_clock_warp(QEMUClock *clock)
{
    int64_t deadline;

    /*
     * There are too many global variables to make the "warp" behavior
     * applicable to other clocks.  But a clock argument removes the
     * need for if statements all over the place.
     */
    if (clock != vm_clock || !use_icount) {
        return;
    }

    /*
     * If the CPUs have been sleeping, advance the vm_clock timer now.  This
     * ensures that the deadline for the timer is computed correctly below.
     * This also makes sure that the insn counter is synchronized before the
     * CPU starts running, in case the CPU is woken by an event other than
     * the earliest vm_clock timer.
     */
    icount_warp_rt(NULL);
    if (!all_cpu_threads_idle() || !qemu_clock_has_timers(vm_clock)) {
        qemu_del_timer(icount_warp_timer);
        return;
    }

    vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
    deadline = qemu_clock_deadline(vm_clock);
    if (deadline > 0) {
        /*
         * Ensure the vm_clock proceeds even when the virtual CPU goes to
         * sleep.  Otherwise, the CPU might be waiting for a future timer
         * interrupt to wake it up, but the interrupt never comes because
         * the vCPU isn't running any insns and thus doesn't advance the
         * vm_clock.
         *
         * An extreme solution for this problem would be to never let VCPUs
         * sleep in icount mode if there is a pending vm_clock timer; rather
         * time could just advance to the next vm_clock event.  Instead, we
         * do stop VCPUs and only advance vm_clock after some "real" time,
         * (related to the time left until the next event) has passed.  This
         * rt_clock timer will do this.  This avoids that the warps are too
         * visible externally---for example, you will not be sending network
         * packets continuously instead of every 100ms.
         */
        qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline);
    } else {
        qemu_notify_event();
    }
}
Exemple #11
0
static void set_next_tick(dp8393xState *s)
{
    uint32_t ticks;
    int64_t delay;

    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
        qemu_del_timer(s->watchdog);
        return;
    }

    ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
    s->wt_last_update = qemu_get_clock(vm_clock);
    delay = get_ticks_per_sec() * ticks / 5000000;
    qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
}
Exemple #12
0
/* Set Clock Comparator */
void HELPER(sckc)(CPUS390XState *env, uint64_t a1)
{
    uint64_t time = cpu_ldq_data(env, a1);

    if (time == -1ULL) {
        return;
    }

    /* difference between now and then */
    time -= clock_value(env);
    /* nanoseconds */
    time = (time * 125) >> 9;

    qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
}
Exemple #13
0
static void rtc_notify_clock_reset(Notifier *notifier, void *data)
{
    RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
    int64_t now = *(int64_t *)data;

    rtc_set_date_from_host(&s->dev);
    s->next_second_time = now + (get_ticks_per_sec() * 99) / 100;
    qemu_mod_timer(s->second_timer2, s->next_second_time);
    rtc_timer_update(s, now);
#ifdef TARGET_I386
    if (rtc_td_hack) {
        rtc_coalesced_timer_update(s);
    }
#endif
}
Exemple #14
0
static void pl031_set_alarm(pl031_state *s)
{
    uint32_t ticks;

    /* The timer wraps around.  This subtraction also wraps in the same way,
       and gives correct results when alarm < now_ticks.  */
    ticks = s->mr - pl031_get_count(s);
    DPRINTF("Alarm set in %ud ticks\n", ticks);
    if (ticks == 0) {
        qemu_del_timer(s->timer);
        pl031_interrupt(s);
    } else {
        int64_t now = qemu_get_clock_ns(rtc_clock);
        qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec());
    }
}
Exemple #15
0
void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
{
    int i;
    uint32_t wake_ccount = env->sregs[CCOUNT] - 1;

    for (i = 0; i < env->config->nccompare; ++i) {
        if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
                wake_ccount - env->sregs[CCOUNT]) {
            wake_ccount = env->sregs[CCOMPARE + i];
        }
    }
    env->wake_ccount = wake_ccount;
    qemu_mod_timer(env->ccompare_timer, env->halt_clock +
            muldiv64(wake_ccount - env->sregs[CCOUNT],
                1000000, env->config->clock_freq_khz));
}
Exemple #16
0
static void qemu_announce_self_once(void *opaque)
{
    static int count = SELF_ANNOUNCE_ROUNDS;
    QEMUTimer *timer = *(QEMUTimer **)opaque;

    qemu_foreach_nic(qemu_announce_self_iter, NULL);

    if (--count) {
        /* delay 50ms, 150ms, 250ms, ... */
        qemu_mod_timer(timer, qemu_get_clock(rt_clock) +
                       50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
    } else {
	    qemu_del_timer(timer);
	    qemu_free_timer(timer);
    }
}
Exemple #17
0
static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
{
    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
    int i;
    uint32_t now_vm;
    uint64_t new_qemu;

    now_vm = s->clock +
            muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());

    for (i = 0; i < 4; i ++) {
        new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
                        get_ticks_per_sec(), s->freq);
        qemu_mod_timer(s->timer[i].qtimer, new_qemu);
    }
}
static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIONet *n = to_virtio_net(vdev);

    if (n->tx_timer_active) {
        virtio_queue_set_notification(vq, 1);
        qemu_del_timer(n->tx_timer);
        n->tx_timer_active = 0;
        virtio_net_flush_tx(n, vq);
    } else {
        qemu_mod_timer(n->tx_timer,
                       qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
        n->tx_timer_active = 1;
        virtio_queue_set_notification(vq, 0);
    }
}
Exemple #19
0
static void mmc_send_command(S5pc1xxMMCState *s)
{
    SDRequest request;
    uint8_t response[16];
    int rlen;

    s->errintsts = 0;
    qemu_mod_timer(s->response_timer, qemu_get_clock(vm_clock));
    if (!s->card)
        return;

    request.cmd = s->cmdreg >> 8;
    request.arg = s->cmdarg;
    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
    rlen = sd_do_command(s->card, &request, response);
    if (rlen < 0)
        goto error;
    if ((s->cmdreg & CMD_RESPONSE) != 0) {
#define RWORD(n) ((n >= 0 ? (response[n] << 24) : 0) \
                  | (response[n + 1] << 16) \
                  | (response[n + 2] << 8) \
                  |  response[n + 3])

        if (rlen == 0)
            goto error;
        if (rlen != 4 && rlen != 16)
            goto error;
        s->response[0] = RWORD(0);
        if (rlen == 4) {
            s->response[1] = s->response[2] = s->response[3] = 0;
        } else {
            s->response[0] = RWORD(11);
            s->response[1] = RWORD(7);
            s->response[2] = RWORD(3);
            s->response[3] = RWORD(-1);
        }
        DPRINTF("Response received\n");
#undef RWORD
    } else {
        DPRINTF("Command sent\n");
    }
    return;

error:
    DPRINTF("Timeout\n");
    s->errintsts |= S5C_HSMMC_EIS_CMDTIMEOUT;
}
Exemple #20
0
QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state)
{
    QEMUFileBuffered *s;

    s = g_malloc0(sizeof(*s));

    s->migration_state = migration_state;
    s->xfer_limit = migration_state->bandwidth_limit / 10;

    s->file = qemu_fopen_ops(s, &buffered_file_ops);

    s->timer = qemu_new_timer_ms(rt_clock, buffered_rate_tick, s);

    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);

    return s->file;
}
Exemple #21
0
static void iscsi_nop_timed_event(void *opaque)
{
    IscsiLun *iscsilun = opaque;

    if (iscsi_get_nops_in_flight(iscsilun->iscsi) > MAX_NOP_FAILURES) {
        error_report("iSCSI: NOP timeout. Reconnecting...");
        iscsi_reconnect(iscsilun->iscsi);
    }

    if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
        error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
        return;
    }

    qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL);
    iscsi_set_events(iscsilun);
}
Exemple #22
0
static void pm_update_sci(PIIX4PMState *s)
{
    int sci_level, pmsts;
    int64_t expire_time;

    pmsts = get_pmsts(s);
    sci_level = (((pmsts & s->pmen) &
                  (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
    qemu_set_irq(s->irq, sci_level);
    /* schedule a timer interruption if needed */
    if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
        expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), PM_FREQ);
        qemu_mod_timer(s->tmr_timer, expire_time);
    } else {
        qemu_del_timer(s->tmr_timer);
    }
}
Exemple #23
0
/* handle update-ended timer */
static void check_update_timer(RTCState *s)
{
    uint64_t next_update_time;
    uint64_t guest_nsec;
    int next_alarm_sec;

    /* From the data sheet: "Holding the dividers in reset prevents
     * interrupts from operating, while setting the SET bit allows"
     * them to occur.  However, it will prevent an alarm interrupt
     * from occurring, because the time of day is not updated.
     */
    if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) {
        qemu_del_timer(s->update_timer);
        return;
    }
    if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
        (s->cmos_data[RTC_REG_B] & REG_B_SET)) {
        qemu_del_timer(s->update_timer);
        return;
    }
    if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
        (s->cmos_data[RTC_REG_C] & REG_C_AF)) {
        qemu_del_timer(s->update_timer);
        return;
    }

    guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC;
    /* if UF is clear, reprogram to next second */
    next_update_time = qemu_get_clock_ns(rtc_clock)
        + NSEC_PER_SEC - guest_nsec;

    /* Compute time of next alarm.  One second is already accounted
     * for in next_update_time.
     */
    next_alarm_sec = get_next_alarm(s);
    s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NSEC_PER_SEC;

    if (s->cmos_data[RTC_REG_C] & REG_C_UF) {
        /* UF is set, but AF is clear.  Program the timer to target
         * the alarm time.  */
        next_update_time = s->next_alarm_time;
    }
    if (next_update_time != qemu_timer_expire_time_ns(s->update_timer)) {
        qemu_mod_timer(s->update_timer, next_update_time);
    }
}
Exemple #24
0
static void buffered_rate_tick(void *opaque)
{
    QEMUFileBuffered *s = opaque;

    if (qemu_file_get_error(s->file)) {
        buffered_close(s);
        return;
    }

    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);

    if (s->freeze_output)
        return;

    s->bytes_xfer = 0;

    buffered_put_buffer(s, NULL, 0, 0);
}
static uint32_t s5l8930_spi_mm_read(void *opaque, target_phys_addr_t offset)
{
    S5L8930SPIState *s = (S5L8930SPIState *)opaque;

//	fprintf(stderr, "%s: base 0x%08x offset 0x%08x\n", __func__, s->base, offset);

    switch (offset) {
    case SPI_CONTROL:
        return s->ctrl;
    case SPI_SETUP:
        return s->setup;
    case SPI_STATUS:
        /* Strange that on fifo empty irq handler doesnt clear irq */
        qemu_irq_lower(s->irq);
        return s->status;
    case SPI_PIN:
        return s->pin;
    case SPI_TXDATA:
        return s->tx_data[0];
    case SPI_RXDATA:
        s->rx_data = pflash_cmd_parse(s->pflash);
        s->status |= pflash_cmd_len(s->pflash) << 11;
        //fprintf(stderr, "%s: rxBuf 0x%08x\n", __func__, s->rx_data);

        /* Queue fifo empty irq */
        if(s->rxFifoCnt == 0x1e) {
            qemu_irq_lower(s->irq);
            qemu_mod_timer(s->timer, qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 1000));
        } else
            s->rxFifoCnt++;
        return s->rx_data;
    case SPI_CLKDIV:
        return s->clkdiv;
    case SPI_CNT:
        return s->cnt;
    case SPI_IDD:
        return s->idd;
    default:
        ;
        //fprintf(stderr, "%s: base 0x%08x offset 0x%08x\n", __func__, s->base, offset);
        //hw_error("s5l8930_spi: bad read offset 0x" TARGET_FMT_plx "\n", offset);
    }
    return 0;
}
static void buffered_rate_tick(void *opaque)
{
    QEMUFileBuffered *s = opaque;

    if (s->has_error)
        return;

    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);

    if (s->freeze_output)
        return;

    s->bytes_xfer = 0;

    buffered_flush(s);

    /* Add some checks around this */
    s->put_ready(s->opaque);
}
static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
{
    VirtIONet *n = opaque;

    if (version_id != 1)
        return -EINVAL;

    virtio_load(&n->vdev, f);

    qemu_get_buffer(f, n->mac, 6);
    n->tx_timer_active = qemu_get_be32(f);

    if (n->tx_timer_active) {
        qemu_mod_timer(n->tx_timer,
                       qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
    }

    return 0;
}
/* timer for waiting the semaphore for sem_retry times try */
static void onedram_wait_semaphore(void *opaque)
{
    S5pc1xxOneDRAMState *s = (S5pc1xxOneDRAMState *)opaque;
    int64_t timeout;

    if(sem_retry <= 0) {
        fprintf(stderr, "time out to wait semaphore from AP\n");
        qemu_del_timer(s->sem_timer);
        sem_retry = 100;
    } else if(onedram_read_sem(s)) {
        sem_retry--;
        timeout = get_ticks_per_sec();
        qemu_mod_timer(s->sem_timer, qemu_get_clock(vm_clock) + TICK_COUNTDOWN);
    } else {
        sem_retry = 100;
        qemu_del_timer(s->sem_timer);
        onedram_fmt_send_cmd(s);
    }
}
Exemple #29
0
RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year)
{
    RTCState *s;

    s = qemu_mallocz(sizeof(RTCState));

    s->irq = irq;
    s->sqw_irq = sqw_irq;
    s->cmos_data[RTC_REG_A] = 0x26;
    s->cmos_data[RTC_REG_B] = 0x02;
    s->cmos_data[RTC_REG_C] = 0x00;
    s->cmos_data[RTC_REG_D] = 0x80;

    s->base_year = base_year;
    rtc_set_date_from_host(s);

    s->periodic_timer = qemu_new_timer(vm_clock,
                                       rtc_periodic_timer, s);
#ifdef TARGET_I386
    if (rtc_td_hack)
        s->coalesced_timer = qemu_new_timer(vm_clock, rtc_coalesced_timer, s);
#endif
    s->second_timer = qemu_new_timer(vm_clock,
                                     rtc_update_second, s);
    s->second_timer2 = qemu_new_timer(vm_clock,
                                      rtc_update_second2, s);

    s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
    qemu_mod_timer(s->second_timer2, s->next_second_time);

    register_ioport_write(base, 2, 1, cmos_ioport_write, s);
    register_ioport_read(base, 2, 1, cmos_ioport_read, s);

    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
#ifdef TARGET_I386
    if (rtc_td_hack)
        register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
#endif
    qemu_register_reset(rtc_reset, s);

    return s;
}
static inline void csrhci_fifo_wake(struct csrhci_s *s)
{
    if (!s->enable || !s->out_len)
        return;

    /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
    if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) &&
                    s->chr.chr_read) {
        s->chr.chr_read(s->chr.handler_opaque,
                        s->outfifo + s->out_start ++, 1);
        s->out_len --;
        if (s->out_start >= s->out_size) {
            s->out_start = 0;
            s->out_size = FIFO_LEN;
        }
    }

    if (s->out_len)
        qemu_mod_timer(s->out_tm, qemu_get_clock(vm_clock) + s->baud_delay);
}