mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-22 10:21:04 +00:00
parent
85c8bd7d7e
commit
80687e702c
@ -71,10 +71,9 @@ For each virtio_device node the following attributes need to be set:
|
|||||||
|
|
||||||
:type:
|
:type:
|
||||||
The Virtio type of device. One can decide in between "console", "net", "gpu",
|
The Virtio type of device. One can decide in between "console", "net", "gpu",
|
||||||
and "block". The "console" type gets mapped to a Genode Terminal session,
|
"input", and "block". The "console" type gets mapped to a Genode Terminal
|
||||||
"net" is mapped to a Nic session, "gpu" is mapped to a Gui session,
|
session, "net" is mapped to a Nic session, "gpu" is mapped to a Gui session,
|
||||||
and "block" to a Block session.
|
"input" to the event part of the Gui session, and "block" to a Block session.
|
||||||
|
|
||||||
|
|
||||||
Additional devices
|
Additional devices
|
||||||
------------------
|
------------------
|
||||||
|
@ -38,7 +38,7 @@ class Vmm::Config
|
|||||||
|
|
||||||
struct Virtio_device : List_model<Virtio_device>::Element
|
struct Virtio_device : List_model<Virtio_device>::Element
|
||||||
{
|
{
|
||||||
enum Type { INVALID, CONSOLE, NET, BLOCK, GPU };
|
enum Type { INVALID, CONSOLE, NET, BLOCK, GPU, INPUT };
|
||||||
|
|
||||||
enum { MMIO_SIZE = 0x200 };
|
enum { MMIO_SIZE = 0x200 };
|
||||||
|
|
||||||
@ -95,6 +95,7 @@ class Vmm::Config
|
|||||||
if (type == "net") t = Virtio_device::NET;
|
if (type == "net") t = Virtio_device::NET;
|
||||||
if (type == "block") t = Virtio_device::BLOCK;
|
if (type == "block") t = Virtio_device::BLOCK;
|
||||||
if (type == "gpu") t = Virtio_device::GPU;
|
if (type == "gpu") t = Virtio_device::GPU;
|
||||||
|
if (type == "input") t = Virtio_device::INPUT;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
|
|||||||
Env & _env;
|
Env & _env;
|
||||||
Heap & _heap;
|
Heap & _heap;
|
||||||
Attached_ram_dataspace & _ram_ds;
|
Attached_ram_dataspace & _ram_ds;
|
||||||
Gui::Connection _gui { _env };
|
Gui::Connection & _gui;
|
||||||
Cpu::Signal_handler<Virtio_gpu_device> _handler;
|
Cpu::Signal_handler<Virtio_gpu_device> _handler;
|
||||||
Constructible<Attached_dataspace> _fb_ds { };
|
Constructible<Attached_dataspace> _fb_ds { };
|
||||||
Framebuffer::Mode _fb_mode { _gui.mode() };
|
Framebuffer::Mode _fb_mode { _gui.mode() };
|
||||||
@ -452,11 +452,12 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
|
|||||||
Ram & ram,
|
Ram & ram,
|
||||||
Env & env,
|
Env & env,
|
||||||
Heap & heap,
|
Heap & heap,
|
||||||
Attached_ram_dataspace & ram_ds)
|
Attached_ram_dataspace & ram_ds,
|
||||||
|
Gui::Connection & gui)
|
||||||
:
|
:
|
||||||
Virtio_device<Virtio_gpu_queue, 2>(name, addr, size,
|
Virtio_device<Virtio_gpu_queue, 2>(name, addr, size,
|
||||||
irq, cpu, bus, ram, GPU),
|
irq, cpu, bus, ram, GPU),
|
||||||
_env(env), _heap(heap), _ram_ds(ram_ds),
|
_env(env), _heap(heap), _ram_ds(ram_ds), _gui(gui),
|
||||||
_handler(cpu, env.ep(), *this, &Virtio_gpu_device::_mode_change)
|
_handler(cpu, env.ep(), *this, &Virtio_gpu_device::_mode_change)
|
||||||
{
|
{
|
||||||
_gui.mode_sigh(_handler);
|
_gui.mode_sigh(_handler);
|
||||||
|
310
repos/os/src/server/vmm/virtio_input.h
Normal file
310
repos/os/src/server/vmm/virtio_input.h
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/*
|
||||||
|
* \brief Virtio Input implementation
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2022-12-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _VIRTIO_INPUT_H_
|
||||||
|
#define _VIRTIO_INPUT_H_
|
||||||
|
|
||||||
|
#include <input/event.h>
|
||||||
|
#include <input_session/client.h>
|
||||||
|
#include <virtio_device.h>
|
||||||
|
|
||||||
|
namespace Vmm {
|
||||||
|
class Virtio_input_device;
|
||||||
|
using namespace Genode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace Linux_evdev
|
||||||
|
{
|
||||||
|
enum Type {
|
||||||
|
EV_SYNC = 0x0,
|
||||||
|
EV_KEY = 0x1,
|
||||||
|
EV_REL = 0x2,
|
||||||
|
EV_ABS = 0x3,
|
||||||
|
EV_REP = 0x14
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Relative {
|
||||||
|
REL_WHEEL = 8,
|
||||||
|
EV_REL_FEATURES = 1U << REL_WHEEL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Absolute {
|
||||||
|
ABS_X = 0,
|
||||||
|
ABS_Y = 1,
|
||||||
|
EV_ABS_FEATURES = (1U << ABS_X) | (1U << ABS_Y)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Vmm::Virtio_input_device : public Virtio_device<Virtio_split_queue, 2>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Env & _env;
|
||||||
|
Heap & _heap;
|
||||||
|
Input::Session_client & _input;
|
||||||
|
Attached_dataspace _input_ds { _env.rm(), _input.dataspace() };
|
||||||
|
Input::Event const * const _events {
|
||||||
|
_input_ds.local_addr<Input::Event>() };
|
||||||
|
|
||||||
|
enum State { READY, IN_MOTION, SYNC };
|
||||||
|
|
||||||
|
State _state { READY };
|
||||||
|
unsigned _num_events { 0U };
|
||||||
|
unsigned _idx_events { 0U };
|
||||||
|
int _motion_y { -1 };
|
||||||
|
|
||||||
|
Cpu::Signal_handler<Virtio_input_device> _handler;
|
||||||
|
|
||||||
|
struct Virtio_input_event : Mmio
|
||||||
|
{
|
||||||
|
enum { SIZE = 8 };
|
||||||
|
|
||||||
|
struct Type : Register<0, 16> {};
|
||||||
|
struct Code : Register<2, 16> {};
|
||||||
|
struct Value : Register<4, 32> {};
|
||||||
|
|
||||||
|
using Mmio::Mmio;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Configuration_area : Mmio_register
|
||||||
|
{
|
||||||
|
Virtio_input_device & dev;
|
||||||
|
|
||||||
|
struct Abs_info
|
||||||
|
{
|
||||||
|
enum { SIZE = 20 };
|
||||||
|
|
||||||
|
uint32_t min;
|
||||||
|
uint32_t max;
|
||||||
|
uint32_t fuzz;
|
||||||
|
uint32_t flat;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Offsets
|
||||||
|
{
|
||||||
|
SELECT = 0,
|
||||||
|
SUB_SELECT = 1,
|
||||||
|
SIZE = 2,
|
||||||
|
DATA = 8,
|
||||||
|
DATA_MAX = DATA + 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Select {
|
||||||
|
UNSET = 0x00,
|
||||||
|
ID_NAME = 0x01,
|
||||||
|
ID_SERIAL = 0x02,
|
||||||
|
ID_DEVIDS = 0x03,
|
||||||
|
PROP_BITS = 0x10,
|
||||||
|
EV_BITS = 0x11,
|
||||||
|
ABS_INFO = 0x12,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t _select { 0 };
|
||||||
|
uint8_t _sub_select { 0 };
|
||||||
|
|
||||||
|
String<16> _name { "vinput0" };
|
||||||
|
String<16> _serial { "serial0" };
|
||||||
|
String<16> _dev_id { "0" };
|
||||||
|
|
||||||
|
uint8_t _size()
|
||||||
|
{
|
||||||
|
using namespace Linux_evdev;
|
||||||
|
|
||||||
|
switch (_select) {
|
||||||
|
case ID_NAME: return _name.length() - 1;
|
||||||
|
case ID_SERIAL: return _serial.length() - 1;
|
||||||
|
case ID_DEVIDS: return _dev_id.length() - 1;
|
||||||
|
case PROP_BITS: return 0; /* Unsupported */
|
||||||
|
case EV_BITS:
|
||||||
|
switch (_sub_select) {
|
||||||
|
case EV_KEY: return 36;
|
||||||
|
case EV_REL: return 2;
|
||||||
|
case EV_ABS: return 1;
|
||||||
|
case EV_REP: return 1;
|
||||||
|
default: return 0; /* Unsupported */
|
||||||
|
};
|
||||||
|
case ABS_INFO: return 20;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
|
||||||
|
error("Unknown size for ", _select, " ", _sub_select);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Register _data(addr_t off)
|
||||||
|
{
|
||||||
|
using namespace Linux_evdev;
|
||||||
|
|
||||||
|
switch (_select) {
|
||||||
|
case ID_NAME:
|
||||||
|
return (off < (_name.length()-1)) ? _name.string()[off] : 0;
|
||||||
|
case ID_SERIAL:
|
||||||
|
return (off < (_serial.length()-1)) ? _serial.string()[off]
|
||||||
|
: 0;
|
||||||
|
case ID_DEVIDS:
|
||||||
|
return (off < (_dev_id.length()-1)) ? _dev_id.string()[off]
|
||||||
|
: 0;
|
||||||
|
case EV_BITS:
|
||||||
|
switch (_sub_select) {
|
||||||
|
case EV_ABS: return EV_ABS_FEATURES;
|
||||||
|
case EV_REL: return EV_REL_FEATURES;
|
||||||
|
case EV_KEY: return 0xffffffff;
|
||||||
|
default: return 0;
|
||||||
|
};
|
||||||
|
case ABS_INFO:
|
||||||
|
switch (_sub_select) {
|
||||||
|
case ABS_X: return (off == 4) ? 1920 : 0;
|
||||||
|
case ABS_Y: return (off == 4) ? 1050 : 0;
|
||||||
|
default: return 0;
|
||||||
|
};
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
|
||||||
|
error("Invalid data offset for selectors ",
|
||||||
|
_select, " ", _sub_select);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Register read(Address_range & range, Cpu&) override
|
||||||
|
{
|
||||||
|
if (range.start == SIZE)
|
||||||
|
return _size();
|
||||||
|
|
||||||
|
if (range.start >= DATA && range.start < DATA_MAX)
|
||||||
|
return _data(range.start-DATA);
|
||||||
|
|
||||||
|
error("Reading from virtio input config space ",
|
||||||
|
"at offset ", range.start, " is not allowed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(Address_range & range, Cpu&, Register v) override
|
||||||
|
{
|
||||||
|
switch (range.start) {
|
||||||
|
case SELECT: _select = v; return;
|
||||||
|
case SUB_SELECT: _sub_select = v; return;
|
||||||
|
default:
|
||||||
|
error("Writing to virtio input config space ",
|
||||||
|
"at offset ", range.start, " is not allowed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration_area(Virtio_input_device & device)
|
||||||
|
: Mmio_register("Input config area",
|
||||||
|
Mmio_register::RO, 0x100, 0xa4),
|
||||||
|
dev(device) { device.add(*this); }
|
||||||
|
} _config_area{ *this };
|
||||||
|
|
||||||
|
void _handle_input()
|
||||||
|
{
|
||||||
|
if (!_queue[0].constructed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool irq = _queue[0]->notify([&] (addr_t addr, size_t size) {
|
||||||
|
if (size < Virtio_input_event::SIZE) {
|
||||||
|
warning("wrong virtioqueue packet size for input ", size);
|
||||||
|
return 0UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Virtio_input_event vie(addr);
|
||||||
|
|
||||||
|
if (_state == IN_MOTION) {
|
||||||
|
vie.write<Virtio_input_event::Type>(Linux_evdev::EV_ABS);
|
||||||
|
vie.write<Virtio_input_event::Code>(Linux_evdev::ABS_Y);
|
||||||
|
vie.write<Virtio_input_event::Value>(_motion_y);
|
||||||
|
_state = SYNC;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_state == SYNC) {
|
||||||
|
vie.write<Virtio_input_event::Type>(Linux_evdev::EV_SYNC);
|
||||||
|
vie.write<Virtio_input_event::Code>(0);
|
||||||
|
vie.write<Virtio_input_event::Value>(0);
|
||||||
|
_state = READY;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_num_events == _idx_events) {
|
||||||
|
_num_events = _input.flush();
|
||||||
|
_idx_events = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_idx_events < _num_events &&
|
||||||
|
!_events[_idx_events].valid())
|
||||||
|
_idx_events++;
|
||||||
|
|
||||||
|
if (_num_events == _idx_events)
|
||||||
|
return 0UL;
|
||||||
|
|
||||||
|
Input::Event const event = _events[_idx_events++];
|
||||||
|
|
||||||
|
auto press = [&] (Input::Keycode key, bool press) {
|
||||||
|
vie.write<Virtio_input_event::Type>(Linux_evdev::EV_KEY);
|
||||||
|
vie.write<Virtio_input_event::Code>(key);
|
||||||
|
vie.write<Virtio_input_event::Value>(press);
|
||||||
|
_state = SYNC;
|
||||||
|
};
|
||||||
|
event.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
|
||||||
|
press(key, true); });
|
||||||
|
event.handle_release([&] (Input::Keycode key) {
|
||||||
|
press(key, false); });
|
||||||
|
event.handle_absolute_motion([&] (int x, int y)
|
||||||
|
{
|
||||||
|
vie.write<Virtio_input_event::Type>(Linux_evdev::EV_ABS);
|
||||||
|
vie.write<Virtio_input_event::Code>(Linux_evdev::ABS_X);
|
||||||
|
vie.write<Virtio_input_event::Value>(x);
|
||||||
|
_motion_y = y;
|
||||||
|
_state = IN_MOTION;
|
||||||
|
});
|
||||||
|
return size;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (irq) _assert_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _notify(unsigned idx) override
|
||||||
|
{
|
||||||
|
if (idx) {
|
||||||
|
error("VirtIO input queue for status event not implemented");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_handle_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Device_id { INPUT = 18 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Virtio_input_device(const char * const name,
|
||||||
|
const uint64_t addr,
|
||||||
|
const uint64_t size,
|
||||||
|
unsigned irq,
|
||||||
|
Cpu & cpu,
|
||||||
|
Mmio_bus & bus,
|
||||||
|
Ram & ram,
|
||||||
|
Env & env,
|
||||||
|
Heap & heap,
|
||||||
|
Input::Session_client & input)
|
||||||
|
:
|
||||||
|
Virtio_device<Virtio_split_queue, 2>(name, addr, size,
|
||||||
|
irq, cpu, bus, ram, INPUT),
|
||||||
|
_env(env), _heap(heap), _input(input),
|
||||||
|
_handler(cpu, env.ep(), *this, &Virtio_input_device::_handle_input)
|
||||||
|
{
|
||||||
|
_input.sigh(_handler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _VIRTIO_INPUT_H_ */
|
@ -17,6 +17,7 @@
|
|||||||
#include <virtio_net.h>
|
#include <virtio_net.h>
|
||||||
#include <virtio_block.h>
|
#include <virtio_block.h>
|
||||||
#include <virtio_gpu.h>
|
#include <virtio_gpu.h>
|
||||||
|
#include <virtio_input.h>
|
||||||
|
|
||||||
using Vmm::Vm;
|
using Vmm::Vm;
|
||||||
|
|
||||||
@ -124,10 +125,18 @@ Vm::Vm(Genode::Env & env, Heap & heap, Config & config)
|
|||||||
_bus, _ram, env, heap));
|
_bus, _ram, env, heap));
|
||||||
return;
|
return;
|
||||||
case Config::Virtio_device::GPU:
|
case Config::Virtio_device::GPU:
|
||||||
|
if (!_gui.constructed()) _gui.construct(env);
|
||||||
_device_list.insert(new (_heap)
|
_device_list.insert(new (_heap)
|
||||||
Virtio_gpu_device(dev.name.string(), (uint64_t)dev.mmio_start,
|
Virtio_gpu_device(dev.name.string(), (uint64_t)dev.mmio_start,
|
||||||
dev.mmio_size, dev.irq, boot_cpu(),
|
dev.mmio_size, dev.irq, boot_cpu(),
|
||||||
_bus, _ram, env, heap, _vm_ram));
|
_bus, _ram, env, heap, _vm_ram, *_gui));
|
||||||
|
return;
|
||||||
|
case Config::Virtio_device::INPUT:
|
||||||
|
if (!_gui.constructed()) _gui.construct(env);
|
||||||
|
_device_list.insert(new (_heap)
|
||||||
|
Virtio_input_device(dev.name.string(), (uint64_t)dev.mmio_start,
|
||||||
|
dev.mmio_size, dev.irq, boot_cpu(),
|
||||||
|
_bus, _ram, env, heap, *_gui->input()));
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <base/attached_ram_dataspace.h>
|
#include <base/attached_ram_dataspace.h>
|
||||||
#include <base/attached_rom_dataspace.h>
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <gui_session/connection.h>
|
||||||
#include <vm_session/connection.h>
|
#include <vm_session/connection.h>
|
||||||
|
|
||||||
namespace Vmm {
|
namespace Vmm {
|
||||||
@ -64,6 +65,8 @@ class Vmm::Vm
|
|||||||
List<Virtio_device_base> _device_list;
|
List<Virtio_device_base> _device_list;
|
||||||
Pl011 _uart;
|
Pl011 _uart;
|
||||||
|
|
||||||
|
Constructible<Gui::Connection> _gui {};
|
||||||
|
|
||||||
addr_t _initrd_offset() const;
|
addr_t _initrd_offset() const;
|
||||||
addr_t _dtb_offset() const;
|
addr_t _dtb_offset() const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user