static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s, int64_t now) { uint64_t ticks; int64_t now_ticks; if (s->tim_arr == 0) { return; } DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1); now_ticks = stm32f2xx_ns_to_ticks(s, now); ticks = s->tim_arr - (now_ticks - s->tick_offset); DB_PRINT("Alarm set in %d ticks\n", (int) ticks); s->hit_time = muldiv64((ticks + (uint64_t) now_ticks) * (s->tim_psc + 1), 1000000000ULL, s->freq_hz); timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hit_time); DB_PRINT("Wait Time: %" PRId64 " ticks\n", s->hit_time); }
static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) { UartState *s = (UartState *)opaque; uint64_t new_rx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int i; if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { return; } if (s->rx_count == RX_FIFO_SIZE) { s->r[R_CISR] |= UART_INTR_ROVR; } else { for (i = 0; i < size; i++) { s->rx_fifo[s->rx_wpos] = buf[i]; s->rx_wpos = (s->rx_wpos + 1) % RX_FIFO_SIZE; s->rx_count++; } timer_mod(s->fifo_trigger_handle, new_rx_time + (s->char_tx_time * 4)); } uart_update_status(s); }
// ----------------------------------------------------------------------------------- // Forward the remaining portion of the packet at the front of our receive buffer onto the // target static void pebble_control_forward_to_target(PebbleControl *s) { if (s->target_send_bytes == 0) { return; } DPRINTF("%s: %d bytes left to send to target\n", __func__, s->target_send_bytes); int can_read_bytes = s->uart_chr_can_read(s->uart); if (can_read_bytes > 0) { can_read_bytes = MIN(can_read_bytes, s->target_send_bytes); s->uart_chr_read(s->uart, s->rcv_char_buf, can_read_bytes); pebble_control_consume_rcv_bytes(s, can_read_bytes); s->target_send_bytes -= can_read_bytes; DPRINTF("%s: sent %d bytes to target, %d remaining\n", __func__, can_read_bytes, s->target_send_bytes); } // If more data to send, set a timer so we run again later if (s->target_send_bytes) { DPRINTF("%s: Scheduling pebble_control_forward_to_target timer\n", __func__); timer_mod(s->target_send_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) + 1); } }
/* * Called when timecmp is written to update the QEMU timer or immediately * trigger timer interrupt if mtimecmp <= current timer value. */ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value) { uint64_t next; uint64_t diff; uint64_t rtc_r = cpu_riscv_read_rtc(); cpu->env.timecmp = value; if (cpu->env.timecmp <= rtc_r) { /* if we're setting an MTIMECMP value in the "past", immediately raise the timer interrupt */ riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1)); return; } /* otherwise, set up the future timer interrupt */ riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0)); diff = cpu->env.timecmp - rtc_r; /* back to ns (note args switched in muldiv64) */ next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(diff, NANOSECONDS_PER_SECOND, SIFIVE_CLINT_TIMEBASE_FREQ); timer_mod(cpu->env.timer, next); }
static void gptm_reload(gptm_state *s, int n, int reset) { int64_t tick; if (reset) tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); else tick = s->tick[n]; if (s->config == 0) { /* 32-bit CountDown. */ uint32_t count; count = s->load[0] | (s->load[1] << 16); tick += (int64_t)count * system_clock_scale; } else if (s->config == 1) { /* 32-bit RTC. 1Hz tick. */ tick += get_ticks_per_sec(); } else if (s->mode[n] == 0xa) { /* PWM mode. Not implemented. */ } else { hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]); } s->tick[n] = tick; timer_mod(s->timer[n], tick); }
static void ptimer_reload(ptimer_state *s) { uint32_t period_frac = s->period_frac; uint64_t period = s->period; if (s->delta == 0) { ptimer_trigger(s); s->delta = s->limit; } if (s->delta == 0 || s->period == 0) { fprintf(stderr, "Timer with period zero, disabling\n"); s->enabled = 0; return; } /* * Artificially limit timeout rate to something * achievable under QEMU. Otherwise, QEMU spends all * its time generating timer interrupts, and there * is no forward progress. * About ten microseconds is the fastest that really works * on the current generation of host machines. */ if (s->enabled == 1 && (s->delta * period < 10000) && !use_icount) { period = 10000 / s->delta; period_frac = 0; } s->last_event = s->next_event; s->next_event = s->last_event + s->delta * period; if (period_frac) { s->next_event += ((int64_t)period_frac * s->delta) >> 32; } timer_mod(s->timer, s->next_event); }
static void balloon_stats_change_timer(VirtIOBalloon *s, int secs) { timer_mod(s->stats_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + secs * 1000); }
static void colo_process_checkpoint(MigrationState *s) { QIOChannelBuffer *bioc; QEMUFile *fb = NULL; int64_t current_time = qemu_clock_get_ms(QEMU_CLOCK_HOST); Error *local_err = NULL; int ret; failover_init_state(); s->rp_state.from_dst_file = qemu_file_get_return_path(s->to_dst_file); if (!s->rp_state.from_dst_file) { error_report("Open QEMUFile from_dst_file failed"); goto out; } /* * Wait for Secondary finish loading VM states and enter COLO * restore. */ colo_receive_check_message(s->rp_state.from_dst_file, COLO_MESSAGE_CHECKPOINT_READY, &local_err); if (local_err) { goto out; } bioc = qio_channel_buffer_new(COLO_BUFFER_BASE_SIZE); fb = qemu_fopen_channel_output(QIO_CHANNEL(bioc)); object_unref(OBJECT(bioc)); qemu_mutex_lock_iothread(); vm_start(); qemu_mutex_unlock_iothread(); trace_colo_vm_state_change("stop", "run"); timer_mod(s->colo_delay_timer, current_time + s->parameters.x_checkpoint_delay); while (s->state == MIGRATION_STATUS_COLO) { if (failover_get_state() != FAILOVER_STATUS_NONE) { error_report("failover request"); goto out; } qemu_sem_wait(&s->colo_checkpoint_sem); ret = colo_do_checkpoint_transaction(s, bioc, fb); if (ret < 0) { goto out; } } out: /* Throw the unreported error message after exited from loop */ if (local_err) { error_report_err(local_err); } if (fb) { qemu_fclose(fb); } timer_del(s->colo_delay_timer); /* Hope this not to be too long to wait here */ qemu_sem_wait(&s->colo_exit_sem); qemu_sem_destroy(&s->colo_exit_sem); /* * Must be called after failover BH is completed, * Or the failover BH may shutdown the wrong fd that * re-used by other threads after we release here. */ if (s->rp_state.from_dst_file) { qemu_fclose(s->rp_state.from_dst_file); } }
/* Try to interpret a whole incoming packet */ static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len) { const uint8_t *cur = buf; uint8_t req = 0; if (!len--) return 0; if (*cur++ != ESC) { while (*cur != ESC) { if (!len--) return 0; cur++; } DPRINTF("Dropped %td bytes!\n", cur - buf); } #define EAT(c) do {\ if (!len--) \ return 0; \ if ((c = *cur++) == ESC) { \ if (!len--) \ return 0; \ if (*cur++ != ESC) { \ DPRINTF("Broken packet %#2x, tossing\n", req); \ if (timer_pending(baum->cellCount_timer)) { \ timer_del(baum->cellCount_timer); \ baum_cellCount_timer_cb(baum); \ } \ return (cur - 2 - buf); \ } \ } \ } while (0) EAT(req); switch (req) { case BAUM_REQ_DisplayData: { uint8_t cells[baum->x * baum->y], c; uint8_t text[baum->x * baum->y]; uint8_t zero[baum->x * baum->y]; int cursor = BRLAPI_CURSOR_OFF; int i; /* Allow 100ms to complete the DisplayData packet */ timer_mod(baum->cellCount_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() / 10); for (i = 0; i < baum->x * baum->y ; i++) { EAT(c); cells[i] = c; if ((c & (BRLAPI_DOT7|BRLAPI_DOT8)) == (BRLAPI_DOT7|BRLAPI_DOT8)) { cursor = i + 1; c &= ~(BRLAPI_DOT7|BRLAPI_DOT8); } if (!(c = nabcc_translation[c])) c = '?'; text[i] = c; } timer_del(baum->cellCount_timer); memset(zero, 0, sizeof(zero)); brlapi_writeArguments_t wa = { .displayNumber = BRLAPI_DISPLAY_DEFAULT, .regionBegin = 1, .regionSize = baum->x * baum->y, .text = (char *)text, .textSize = baum->x * baum->y, .andMask = zero, .orMask = cells, .cursor = cursor, .charset = (char *)"ISO-8859-1", }; if (brlapi__write(baum->brlapi, &wa) == -1) brlapi_perror("baum brlapi_write"); break; } case BAUM_REQ_SetMode: { uint8_t mode, setting; DPRINTF("SetMode\n"); EAT(mode); EAT(setting); /* ignore */ break; } case BAUM_REQ_SetProtocol: { uint8_t protocol; DPRINTF("SetProtocol\n"); EAT(protocol); /* ignore */ break; } case BAUM_REQ_GetDeviceIdentity: { uint8_t identity[17] = { BAUM_RSP_DeviceIdentity, 'B','a','u','m',' ','V','a','r','i','o' }; DPRINTF("GetDeviceIdentity\n"); identity[11] = '0' + baum->x / 10; identity[12] = '0' + baum->x % 10; baum_write_packet(baum, identity, sizeof(identity)); break; } case BAUM_REQ_GetVersionNumber: { uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */ DPRINTF("GetVersionNumber\n"); baum_write_packet(baum, version, sizeof(version)); break; } case BAUM_REQ_GetSerialNumber: { uint8_t serial[] = { BAUM_RSP_SerialNumber, '0','0','0','0','0','0','0','0' }; DPRINTF("GetSerialNumber\n"); baum_write_packet(baum, serial, sizeof(serial)); break; } case BAUM_REQ_GetKeys: { DPRINTF("Get%0#2x\n", req); /* ignore */ break; } default: DPRINTF("unrecognized request %0#2x\n", req); do if (!len--) return 0; while (*cur++ != ESC); cur--; break; } return cur - buf; } /* The other end is writing some data. Store it and try to interpret */ static int baum_write(CharDriverState *chr, const uint8_t *buf, int len) { BaumDriverState *baum = chr->opaque; int tocopy, cur, eaten, orig_len = len; if (!len) return 0; if (!baum->brlapi) return len; while (len) { /* Complete our buffer as much as possible */ tocopy = len; if (tocopy > BUF_SIZE - baum->in_buf_used) tocopy = BUF_SIZE - baum->in_buf_used; memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy); baum->in_buf_used += tocopy; buf += tocopy; len -= tocopy; /* Interpret it as much as possible */ cur = 0; while (cur < baum->in_buf_used && (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur))) cur += eaten; /* Shift the remainder */ if (cur) { memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur); baum->in_buf_used -= cur; } /* And continue if any data left */ } return orig_len; }
static void tusb_async_writew(void *opaque, hwaddr addr, uint32_t value) { TUSBState *s = (TUSBState *) opaque; int offset = addr & 0xfff; int epnum; switch (offset) { case TUSB_VLYNQ_CTRL: break; case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): musb_write[2](s->musb, offset & 0x1ff, value); break; case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value); break; case TUSB_DEV_CONF: s->dev_config = value; s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE); if (value & TUSB_DEV_CONF_PROD_TEST_MODE) hw_error("%s: Product Test mode not allowed\n", __FUNCTION__); break; case TUSB_PHY_OTG_CTRL_ENABLE: case TUSB_PHY_OTG_CTRL: return; /* TODO */ case TUSB_DEV_OTG_TIMER: s->otg_timer_val = value; if (value & TUSB_DEV_OTG_TIMER_ENABLE) timer_mod(s->otg_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(TUSB_DEV_OTG_TIMER_VAL(value), NANOSECONDS_PER_SECOND, TUSB_DEVCLOCK)); else timer_del(s->otg_timer); break; case TUSB_PRCM_CONF: s->prcm_config = value; break; case TUSB_PRCM_MNGMT: s->prcm_mngmt = value; break; case TUSB_PRCM_WAKEUP_CLEAR: break; case TUSB_PRCM_WAKEUP_MASK: s->wkup_mask = value; break; case TUSB_PULLUP_1_CTRL: s->pullup[0] = value; break; case TUSB_PULLUP_2_CTRL: s->pullup[1] = value; break; case TUSB_INT_CTRL_CONF: s->control_config = value; tusb_intr_update(s); break; case TUSB_USBIP_INT_SET: s->usbip_intr |= value; tusb_usbip_intr_update(s); break; case TUSB_USBIP_INT_CLEAR: s->usbip_intr &= ~value; tusb_usbip_intr_update(s); musb_core_intr_clear(s->musb, ~value); break; case TUSB_USBIP_INT_MASK: s->usbip_mask = value; tusb_usbip_intr_update(s); break; case TUSB_DMA_INT_SET: s->dma_intr |= value; tusb_dma_intr_update(s); break; case TUSB_DMA_INT_CLEAR: s->dma_intr &= ~value; tusb_dma_intr_update(s); break; case TUSB_DMA_INT_MASK: s->dma_mask = value; tusb_dma_intr_update(s); break; case TUSB_GPIO_INT_SET: s->gpio_intr |= value; tusb_gpio_intr_update(s); break; case TUSB_GPIO_INT_CLEAR: s->gpio_intr &= ~value; tusb_gpio_intr_update(s); break; case TUSB_GPIO_INT_MASK: s->gpio_mask = value; tusb_gpio_intr_update(s); break; case TUSB_INT_SRC_SET: s->intr |= value; tusb_intr_update(s); break; case TUSB_INT_SRC_CLEAR: s->intr &= ~value; tusb_intr_update(s); break; case TUSB_INT_MASK: s->mask = value; tusb_intr_update(s); break; case TUSB_GPIO_CONF: s->gpio_config = value; break; case TUSB_DMA_REQ_CONF: s->dma_config = value; break; case TUSB_EP0_CONF: s->ep0_config = value & 0x1ff; musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value), value & TUSB_EP0_CONFIG_DIR_TX); break; case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b): epnum = (offset - TUSB_EP_IN_SIZE) >> 2; s->tx_config[epnum] = value; musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1); break; case TUSB_DMA_EP_MAP: s->dma_map = value; break; case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b): epnum = (offset - TUSB_EP_OUT_SIZE) >> 2; s->rx_config[epnum] = value; musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0); break; case TUSB_EP_MAX_PACKET_SIZE_OFFSET ... (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b): return; /* TODO */ case TUSB_WAIT_COUNT: return; /* TODO */ case TUSB_SCRATCH_PAD: s->scratch = value; break; case TUSB_PROD_TEST_RESET: s->test_reset = value; break; default: printf("%s: unknown register at %03x\n", __FUNCTION__, offset); return; } }
static void colo_process_checkpoint(MigrationState *s) { QIOChannelBuffer *bioc; QEMUFile *fb = NULL; int64_t current_time = qemu_clock_get_ms(QEMU_CLOCK_HOST); Error *local_err = NULL; int ret; failover_init_state(); s->rp_state.from_dst_file = qemu_file_get_return_path(s->to_dst_file); if (!s->rp_state.from_dst_file) { error_report("Open QEMUFile from_dst_file failed"); goto out; } packets_compare_notifier.notify = colo_compare_notify_checkpoint; colo_compare_register_notifier(&packets_compare_notifier); /* * Wait for Secondary finish loading VM states and enter COLO * restore. */ colo_receive_check_message(s->rp_state.from_dst_file, COLO_MESSAGE_CHECKPOINT_READY, &local_err); if (local_err) { goto out; } bioc = qio_channel_buffer_new(COLO_BUFFER_BASE_SIZE); fb = qemu_fopen_channel_output(QIO_CHANNEL(bioc)); object_unref(OBJECT(bioc)); qemu_mutex_lock_iothread(); #ifdef CONFIG_REPLICATION replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); if (local_err) { qemu_mutex_unlock_iothread(); goto out; } #else abort(); #endif vm_start(); qemu_mutex_unlock_iothread(); trace_colo_vm_state_change("stop", "run"); timer_mod(s->colo_delay_timer, current_time + s->parameters.x_checkpoint_delay); while (s->state == MIGRATION_STATUS_COLO) { if (failover_get_state() != FAILOVER_STATUS_NONE) { error_report("failover request"); goto out; } qemu_sem_wait(&s->colo_checkpoint_sem); if (s->state != MIGRATION_STATUS_COLO) { goto out; } ret = colo_do_checkpoint_transaction(s, bioc, fb); if (ret < 0) { goto out; } } out: /* Throw the unreported error message after exited from loop */ if (local_err) { error_report_err(local_err); } if (fb) { qemu_fclose(fb); } /* * There are only two reasons we can get here, some error happened * or the user triggered failover. */ switch (failover_get_state()) { case FAILOVER_STATUS_NONE: qapi_event_send_colo_exit(COLO_MODE_PRIMARY, COLO_EXIT_REASON_ERROR); break; case FAILOVER_STATUS_REQUIRE: qapi_event_send_colo_exit(COLO_MODE_PRIMARY, COLO_EXIT_REASON_REQUEST); break; default: abort(); } /* Hope this not to be too long to wait here */ qemu_sem_wait(&s->colo_exit_sem); qemu_sem_destroy(&s->colo_exit_sem); /* * It is safe to unregister notifier after failover finished. * Besides, colo_delay_timer and colo_checkpoint_sem can't be * released befor unregister notifier, or there will be use-after-free * error. */ colo_compare_unregister_notifier(&packets_compare_notifier); timer_del(s->colo_delay_timer); timer_free(s->colo_delay_timer); qemu_sem_destroy(&s->colo_checkpoint_sem); /* * Must be called after failover BH is completed, * Or the failover BH may shutdown the wrong fd that * re-used by other threads after we release here. */ if (s->rp_state.from_dst_file) { qemu_fclose(s->rp_state.from_dst_file); } }
void qemu_clock_warp(QEMUClockType type) { 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 (type != QEMU_CLOCK_VIRTUAL || !use_icount) { return; } /* * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL 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 QEMU_CLOCK_VIRTUAL timer. */ icount_warp_rt(NULL); if (!all_cpu_threads_idle() || !qemu_clock_has_timers(QEMU_CLOCK_VIRTUAL)) { timer_del(icount_warp_timer); return; } if (qtest_enabled()) { /* When testing, qtest commands advance icount. */ return; } vm_clock_warp_start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); /* We want to use the earliest deadline from ALL vm_clocks */ deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); /* Maintain prior (possibly buggy) behaviour where if no deadline * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than * INT32_MAX nanoseconds ahead, we still use INT32_MAX * nanoseconds. */ if ((deadline < 0) || (deadline > INT32_MAX)) { deadline = INT32_MAX; } if (deadline > 0) { /* * Ensure QEMU_CLOCK_VIRTUAL 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 * QEMU_CLOCK_VIRTUAL. * * An extreme solution for this problem would be to never let VCPUs * sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL * timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL * event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL * after some e"real" time, (related to the time left until the next * event) has passed. The QEMU_CLOCK_REALTIME timer will do this. * This avoids that the warps are visible externally; for example, * you will not be sending network packets continuously instead of * every 100ms. */ timer_mod(icount_warp_timer, vm_clock_warp_start + deadline); } else if (deadline == 0) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } }
static void icount_adjust_rt(void *opaque) { timer_mod(icount_rt_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); icount_adjust(); }
static inline void tco_timer_reload(TCOIORegs *tr) { tr->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ((int64_t)(tr->tco.tmr & TCO_TMR_MASK) * TCO_TICK_NSEC); timer_mod(tr->tco_timer, tr->expire_time); }
static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, unsigned size) { AspeedWDTState *s = ASPEED_WDT(opaque); bool en = data & BIT(0); bool pclk = !(data & BIT(4)); switch (offset) { case WDT_STATUS: qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only reg at offset 0x%" HWADDR_PRIx "\n", __func__, offset); break; case WDT_RELOAD_VALUE: s->reg_reload_value = data; break; case WDT_RESTART: if ((data & 0xFFFF) == 0x4755) { uint32_t reload; s->reg_status = s->reg_reload_value; if (pclk) { reload = muldiv64(s->reg_reload_value, NANOSECONDS_PER_SECOND, PCLK_HZ) ; } else { reload = s->reg_reload_value * 1000; } if (s->enabled) { timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload); } } break; case WDT_CTRL: if (en && !s->enabled) { uint32_t reload; if (pclk) { reload = muldiv64(s->reg_reload_value, NANOSECONDS_PER_SECOND, PCLK_HZ) ; } else { reload = s->reg_reload_value * 1000; } s->enabled = true; timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload); } else if (!en && s->enabled) { s->enabled = false; timer_del(s->timer); } break; case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: case WDT_RESET_WDITH: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n", __func__, offset); break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", __func__, offset); } return; }
/* this function is called periodically to send sensor reports * to the HAL module, and re-arm the timer if necessary */ static void _hwSensorClient_tick( void* opaque ) { HwSensorClient* cl = opaque; HwSensors* hw = cl->sensors; int64_t delay = cl->delay_ms; int64_t now_ns; uint32_t mask = cl->enabledMask; Sensor* sensor; char buffer[128]; if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_ACCELERATION)) { sensor = &hw->sensors[ANDROID_SENSOR_ACCELERATION]; snprintf(buffer, sizeof buffer, "acceleration:%g:%g:%g", sensor->u.acceleration.x, sensor->u.acceleration.y, sensor->u.acceleration.z); _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer)); } if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_MAGNETIC_FIELD)) { sensor = &hw->sensors[ANDROID_SENSOR_MAGNETIC_FIELD]; /* NOTE: sensors HAL expects "magnetic", not "magnetic-field" name here. */ snprintf(buffer, sizeof buffer, "magnetic:%g:%g:%g", sensor->u.magnetic.x, sensor->u.magnetic.y, sensor->u.magnetic.z); _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer)); } if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_ORIENTATION)) { sensor = &hw->sensors[ANDROID_SENSOR_ORIENTATION]; snprintf(buffer, sizeof buffer, "orientation:%g:%g:%g", sensor->u.orientation.azimuth, sensor->u.orientation.pitch, sensor->u.orientation.roll); _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer)); } if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_TEMPERATURE)) { sensor = &hw->sensors[ANDROID_SENSOR_TEMPERATURE]; snprintf(buffer, sizeof buffer, "temperature:%g", sensor->u.temperature.celsius); _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer)); } if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_PROXIMITY)) { sensor = &hw->sensors[ANDROID_SENSOR_PROXIMITY]; snprintf(buffer, sizeof buffer, "proximity:%g", sensor->u.proximity.value); _hwSensorClient_send(cl, (uint8_t*) buffer, strlen(buffer)); } now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); snprintf(buffer, sizeof buffer, "sync:%" PRId64, now_ns/1000); _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer)); /* rearm timer, use a minimum delay of 20 ms, just to * be safe. */ if (mask == 0) return; if (delay < 20) delay = 20; delay *= 1000000LL; /* convert to nanoseconds */ timer_mod(cl->timer, now_ns + delay); }