Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions devices/common/viacuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -790,15 +790,27 @@ void ViaCuda::pseudo_command() {
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_SET_POWER_MESSAGES:
LOG_F(WARNING, "Cuda: unsupported pseudo command 0x%X SET_POWER_MESSAGES", cmd);
this->power_messages_enabled = !!this->in_buf[2];
LOG_F(INFO, "Cuda: power messages %s", this->power_messages_enabled ? "enabled" : "disabled");
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_READ_WRITE_I2C:
response_header(CUDA_PKT_PSEUDO, 0);
i2c_simple_transaction(this->in_buf[2], &this->in_buf[3], this->in_count - 3);
break;
case CUDA_TIMER_TICKLE:
LOG_F(WARNING, "Cuda: unsupported pseudo command 0x%X TIMER_TICKLE - Byte Sent: 0x%02x", cmd, this->in_buf[2]);
// The guest re-arms the Cuda shutdown watchdog on every tickle; the
// firmware counts it down at 16 counts/sec and powers the machine off
// when it reaches zero. We track the count so an arm value change is
// visible in the log, but never act on expiry to avoid spurious
// power-offs if the guest stops tickling.
if (this->tickle_value != this->in_buf[2]) {
this->tickle_value = this->in_buf[2];
LOG_F(INFO, "Cuda: timer tickle set to %d counts (%.1f s)", this->tickle_value,
(double)this->tickle_value / 16.0);
} else {
LOG_F(9, "Cuda: timer tickle");
}
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_COMB_FMT_I2C:
Expand Down
2 changes: 2 additions & 0 deletions devices/common/viacuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ class ViaCuda : public I2CBus {
bool one_sec_missed = false; // ERS: missed pkt -> fallback to mode $01
bool file_server = false;
bool mono_stable = false;
bool power_messages_enabled = false;
uint8_t tickle_value = 0; // last shutdown watchdog count from the guest
uint8_t ipl_level = 0;
uint16_t device_mask = 0;

Expand Down
55 changes: 35 additions & 20 deletions devices/sound/soundserver_cubeb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,22 +167,26 @@ static void status_callback(cubeb_stream *stream, void *user_data, cubeb_state s

int SoundServer::open_out_stream(uint32_t sample_rate, DmaOutChannel *dma_ch)
{
if (is_deterministic) {
impl->deterministic_poll_cb = [dma_ch] {
if (!dma_ch->is_out_active()) {
return;
}
// Drain the DMA buffer, but don't do anything else.
while(1) {
uint8_t *chunk;
uint32_t chunk_size;
if (DmaPullResult::MoreData == dma_ch->pull_data(1024, &chunk_size, &chunk)) {
;
} else {
break;
}
// Set up a cyclic-timer DMA drain callback. It keeps the guest sound DMA
// advancing even if the host audio stream cannot be started, otherwise
// the guest sound driver would stall forever waiting for DMA interrupts.
impl->deterministic_poll_cb = [dma_ch] {
if (!dma_ch->is_out_active()) {
return;
}
// Drain the DMA buffer, but don't do anything else.
while(1) {
uint8_t *chunk;
uint32_t chunk_size;
if (DmaPullResult::MoreData == dma_ch->pull_data(1024, &chunk_size, &chunk)) {
;
} else {
break;
}
};
}
};

if (is_deterministic) {
impl->status = SND_STREAM_OPENED;
LOG_F(9, "Deterministic sound output callback set up.");
return 0;
Expand Down Expand Up @@ -228,16 +232,27 @@ int SoundServer::start_out_stream()
TimerManager::get_instance()->add_cyclic_timer(MSECS_TO_NSECS(10), impl->deterministic_poll_cb);
return 0;
}
return cubeb_stream_start(impl->out_stream);
int res = cubeb_stream_start(impl->out_stream);
if (res != CUBEB_OK) {
// Fall back to draining the guest sound DMA via a cyclic timer so
// that the guest sound driver does not stall waiting for DMA progress
// that the failed host stream will never provide.
if (!impl->deterministic_poll_timer) {
impl->deterministic_poll_timer =
TimerManager::get_instance()->add_cyclic_timer(MSECS_TO_NSECS(10), impl->deterministic_poll_cb);
LOG_F(9, "Host sound output stream start failed; falling back to cyclic DMA drain.");
}
}
return res;
}

void SoundServer::close_out_stream()
{
if (!impl->out_stream)
return;
if (is_deterministic) {
LOG_F(9, "Stopping sound output deterministic polling.");
if (impl->deterministic_poll_timer) {
TimerManager::get_instance()->cancel_timer(impl->deterministic_poll_timer);
impl->deterministic_poll_timer = 0;
}
if (!impl->out_stream) {
impl->status = SND_STREAM_CLOSED;
return;
}
Expand Down
Loading