blob: 3ab1a81a45aeb44bc2fa4ad79bc0d6fc9f0ca04f [file] [log] [blame]
// Copyright 2018 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 <virtio/input.h>
#include "garnet/bin/guest/vmm/device/input.h"
#include "garnet/bin/guest/vmm/device/test_with_device.h"
#include "garnet/bin/guest/vmm/device/virtio_queue_fake.h"
static constexpr char kVirtioInputUrl[] =
"fuchsia-pkg://fuchsia.com/virtio_input#meta/virtio_input.cmx";
static constexpr uint16_t kNumQueues = 1;
static constexpr uint16_t kQueueSize = 16;
class VirtioInputTest : public TestWithDevice {
protected:
VirtioInputTest()
: event_queue_(phys_mem_, PAGE_SIZE * kNumQueues, kQueueSize) {}
void SetUp() override {
// Launch device process.
fuchsia::guest::device::StartInfo start_info;
zx_status_t status =
LaunchDevice(kVirtioInputUrl, event_queue_.end(), &start_info);
ASSERT_EQ(ZX_OK, status);
// Start device execution.
services.ConnectToService(view_listener_.NewRequest());
services.ConnectToService(input_.NewRequest());
status = input_->Start(std::move(start_info));
ASSERT_EQ(ZX_OK, status);
// Configure device queues.
VirtioQueueFake* queues[kNumQueues] = {&event_queue_};
for (size_t i = 0; i < kNumQueues; i++) {
auto q = queues[i];
q->Configure(PAGE_SIZE * i, PAGE_SIZE);
status = input_->ConfigureQueue(i, q->size(), q->desc(), q->avail(),
q->used());
ASSERT_EQ(ZX_OK, status);
}
}
fuchsia::guest::device::VirtioInputSyncPtr input_;
fuchsia::guest::device::ViewListenerSyncPtr view_listener_;
VirtioQueueFake event_queue_;
};
TEST_F(VirtioInputTest, Keyboard) {
fuchsia::ui::input::InputEvent fuchsia_event;
fuchsia_event.set_keyboard({
.phase = fuchsia::ui::input::KeyboardEventPhase::PRESSED,
.hid_usage = 4,
});
view_listener_->OnInputEvent(std::move(fuchsia_event));
virtio_input_event_t* event_1;
virtio_input_event_t* event_2;
zx_status_t status = DescriptorChainBuilder(event_queue_)
.AppendWritableDescriptor(&event_1, sizeof(*event_1))
.AppendWritableDescriptor(&event_2, sizeof(*event_2))
.Build();
ASSERT_EQ(ZX_OK, status);
status = input_->NotifyQueue(0);
ASSERT_EQ(ZX_OK, status);
status = WaitOnInterrupt();
ASSERT_EQ(ZX_OK, status);
EXPECT_EQ(VIRTIO_INPUT_EV_KEY, event_1->type);
EXPECT_EQ(30, event_1->code);
EXPECT_EQ(VIRTIO_INPUT_EV_KEY_PRESSED, event_1->value);
EXPECT_EQ(VIRTIO_INPUT_EV_SYN, event_2->type);
}
TEST_F(VirtioInputTest, PointerMove) {
view_listener_->OnSizeChanged({1, 1});
fuchsia::ui::input::InputEvent fuchsia_event;
fuchsia_event.set_pointer({
.phase = fuchsia::ui::input::PointerEventPhase::MOVE,
.x = 0.25,
.y = 0.5,
});
view_listener_->OnInputEvent(std::move(fuchsia_event));
virtio_input_event_t* event_1;
virtio_input_event_t* event_2;
virtio_input_event_t* event_3;
zx_status_t status = DescriptorChainBuilder(event_queue_)
.AppendWritableDescriptor(&event_1, sizeof(*event_1))
.AppendWritableDescriptor(&event_2, sizeof(*event_2))
.AppendWritableDescriptor(&event_3, sizeof(*event_3))
.Build();
ASSERT_EQ(ZX_OK, status);
status = input_->NotifyQueue(0);
ASSERT_EQ(ZX_OK, status);
status = WaitOnInterrupt();
ASSERT_EQ(ZX_OK, status);
EXPECT_EQ(VIRTIO_INPUT_EV_ABS, event_1->type);
EXPECT_EQ(VIRTIO_INPUT_EV_ABS_X, event_1->code);
EXPECT_EQ(std::ceil(kInputAbsMaxX * fuchsia_event.pointer().x),
event_1->value);
EXPECT_EQ(VIRTIO_INPUT_EV_ABS, event_2->type);
EXPECT_EQ(VIRTIO_INPUT_EV_ABS_Y, event_2->code);
EXPECT_EQ(std::ceil(kInputAbsMaxY * fuchsia_event.pointer().y),
event_2->value);
EXPECT_EQ(VIRTIO_INPUT_EV_SYN, event_3->type);
}
TEST_F(VirtioInputTest, PointerUp) {
view_listener_->OnSizeChanged({1, 1});
fuchsia::ui::input::InputEvent fuchsia_event;
fuchsia_event.set_pointer({
.phase = fuchsia::ui::input::PointerEventPhase::UP,
.x = 0.25,
.y = 0.5,
});
view_listener_->OnInputEvent(std::move(fuchsia_event));
virtio_input_event_t* event_1;
virtio_input_event_t* event_2;
virtio_input_event_t* event_3;
virtio_input_event_t* event_4;
zx_status_t status = DescriptorChainBuilder(event_queue_)
.AppendWritableDescriptor(&event_1, sizeof(*event_1))
.AppendWritableDescriptor(&event_2, sizeof(*event_2))
.AppendWritableDescriptor(&event_3, sizeof(*event_3))
.AppendWritableDescriptor(&event_4, sizeof(*event_4))
.Build();
ASSERT_EQ(ZX_OK, status);
status = input_->NotifyQueue(0);
ASSERT_EQ(ZX_OK, status);
status = WaitOnInterrupt();
ASSERT_EQ(ZX_OK, status);
EXPECT_EQ(VIRTIO_INPUT_EV_ABS, event_1->type);
EXPECT_EQ(VIRTIO_INPUT_EV_ABS_X, event_1->code);
EXPECT_EQ(std::ceil(kInputAbsMaxX * fuchsia_event.pointer().x),
event_1->value);
EXPECT_EQ(VIRTIO_INPUT_EV_ABS, event_2->type);
EXPECT_EQ(VIRTIO_INPUT_EV_ABS_Y, event_2->code);
EXPECT_EQ(std::ceil(kInputAbsMaxY * fuchsia_event.pointer().y),
event_2->value);
EXPECT_EQ(VIRTIO_INPUT_EV_KEY, event_3->type);
EXPECT_EQ(kButtonTouchCode, event_3->code);
EXPECT_EQ(VIRTIO_INPUT_EV_KEY_RELEASED, event_3->value);
EXPECT_EQ(VIRTIO_INPUT_EV_SYN, event_4->type);
}