blob: d85df28e2313a1c5e406ac75d3eaef8b7a7b9773 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/virtualization/bin/vmm/controller/virtio_gpu.h"
#include <fuchsia/ui/app/cpp/fidl.h>
static constexpr char kVirtioGpuUrl[] = "fuchsia-pkg://fuchsia.com/virtio_gpu#meta/virtio_gpu.cmx";
VirtioGpu::VirtioGpu(const PhysMem& phys_mem)
: VirtioComponentDevice(phys_mem, 0 /* device_features */,
fit::bind_member(this, &VirtioGpu::ConfigureQueue),
fit::bind_member(this, &VirtioGpu::Ready)) {
config_.num_scanouts = 1;
}
zx_status_t VirtioGpu::AddPublicService(sys::ComponentContext* context) {
zx_status_t status = context->outgoing()->AddPublicService(
fidl::InterfaceRequestHandler<fuchsia::ui::app::ViewProvider>(
[this](auto request) { services_->Connect(std::move(request)); }));
if (status != ZX_OK) {
return status;
}
return context->outgoing()->AddPublicService(
fidl::InterfaceRequestHandler<fuchsia::ui::views::View>(
[this](auto request) { services_->Connect(std::move(request)); }));
}
zx_status_t VirtioGpu::Start(
const zx::guest& guest,
fidl::InterfaceHandle<fuchsia::virtualization::hardware::KeyboardListener> keyboard_listener,
fidl::InterfaceHandle<fuchsia::virtualization::hardware::PointerListener> pointer_listener,
fuchsia::sys::Launcher* launcher, async_dispatcher_t* dispatcher) {
fuchsia::sys::LaunchInfo launch_info;
launch_info.url = kVirtioGpuUrl;
services_ = sys::ServiceDirectory::CreateWithRequest(&launch_info.directory_request);
launcher->CreateComponent(std::move(launch_info), controller_.NewRequest());
services_->Connect(gpu_.NewRequest());
services_->Connect(events_.NewRequest());
events_.events().OnConfigChanged = fit::bind_member(this, &VirtioGpu::OnConfigChanged);
fuchsia::virtualization::hardware::StartInfo start_info;
zx_status_t status = PrepStart(guest, dispatcher, &start_info);
if (status != ZX_OK) {
return status;
}
return gpu_->Start(std::move(start_info), std::move(keyboard_listener),
std::move(pointer_listener));
}
zx_status_t VirtioGpu::ConfigureQueue(uint16_t queue, uint16_t size, zx_gpaddr_t desc,
zx_gpaddr_t avail, zx_gpaddr_t used) {
return gpu_->ConfigureQueue(queue, size, desc, avail, used);
}
zx_status_t VirtioGpu::Ready(uint32_t negotiated_features) {
State prev_state = state_;
state_ = State::READY;
if (prev_state == State::CONFIG_READY) {
OnConfigChanged();
}
return gpu_->Ready(negotiated_features);
}
void VirtioGpu::OnConfigChanged() {
if (state_ != State::READY) {
state_ = State::CONFIG_READY;
return;
}
{
std::lock_guard<std::mutex> lock(device_config_.mutex);
config_.events_read |= VIRTIO_GPU_EVENT_DISPLAY;
}
// Send a config change interrupt to the guest.
zx_status_t status = Interrupt(VirtioQueue::SET_CONFIG | VirtioQueue::TRY_INTERRUPT);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to generate configuration interrupt " << status;
}
}