mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 19:38:12 +00:00
Kernel: Add support for reading from VirtIOConsole
This allows two-way communication with the host through a VirtIOConsole. This is necessary for features like clipboard sharing.
This commit is contained in:
parent
1c06d77262
commit
1492bb2fd6
5 changed files with 74 additions and 8 deletions
|
@ -43,6 +43,8 @@ UNMAP_AFTER_INIT VirtIOConsole::VirtIOConsole(PCI::Address address)
|
|||
finish_init();
|
||||
m_receive_buffer = make<RingBuffer>("VirtIOConsole Receive", RINGBUFFER_SIZE);
|
||||
m_transmit_buffer = make<RingBuffer>("VirtIOConsole Transmit", RINGBUFFER_SIZE);
|
||||
|
||||
init_receive_buffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +53,18 @@ VirtIOConsole::~VirtIOConsole()
|
|||
{
|
||||
}
|
||||
|
||||
void VirtIOConsole::init_receive_buffer()
|
||||
{
|
||||
auto& queue = get_queue(RECEIVEQ);
|
||||
ScopedSpinLock queue_lock(queue.lock());
|
||||
VirtIOQueueChain chain(queue);
|
||||
|
||||
auto buffer_start = m_receive_buffer->start_of_region();
|
||||
auto did_add_buffer = chain.add_buffer_to_chain(buffer_start, RINGBUFFER_SIZE, BufferType::DeviceWritable);
|
||||
VERIFY(did_add_buffer);
|
||||
supply_chain_and_notify(RECEIVEQ, chain);
|
||||
}
|
||||
|
||||
bool VirtIOConsole::handle_device_config_change()
|
||||
{
|
||||
dbgln("VirtIOConsole: Handle device config change");
|
||||
|
@ -63,8 +77,27 @@ void VirtIOConsole::handle_queue_update(u16 queue_index)
|
|||
VERIFY(queue_index <= TRANSMITQ);
|
||||
switch (queue_index) {
|
||||
case RECEIVEQ: {
|
||||
ScopedSpinLock lock(get_queue(RECEIVEQ).lock());
|
||||
get_queue(RECEIVEQ).discard_used_buffers(); // TODO: do something with incoming data (users writing into qemu console) instead of just clearing
|
||||
auto& queue = get_queue(RECEIVEQ);
|
||||
ScopedSpinLock queue_lock(queue.lock());
|
||||
size_t used;
|
||||
VirtIOQueueChain popped_chain = queue.pop_used_buffer_chain(used);
|
||||
|
||||
ScopedSpinLock ringbuffer_lock(m_receive_buffer->lock());
|
||||
|
||||
auto used_space = m_receive_buffer->reserve_space(used).value();
|
||||
auto remaining_space = RINGBUFFER_SIZE - used;
|
||||
|
||||
// Our algorithm always has only one buffer in the queue.
|
||||
VERIFY(!queue.new_data_available());
|
||||
popped_chain.release_buffer_slots_to_queue();
|
||||
|
||||
VirtIOQueueChain new_chain(queue);
|
||||
if (remaining_space != 0) {
|
||||
new_chain.add_buffer_to_chain(used_space.offset(used), remaining_space, BufferType::DeviceWritable);
|
||||
supply_chain_and_notify(RECEIVEQ, new_chain);
|
||||
}
|
||||
|
||||
evaluate_block_conditions();
|
||||
break;
|
||||
}
|
||||
case TRANSMITQ: {
|
||||
|
@ -91,12 +124,23 @@ void VirtIOConsole::handle_queue_update(u16 queue_index)
|
|||
|
||||
bool VirtIOConsole::can_read(const FileDescription&, size_t) const
|
||||
{
|
||||
return true;
|
||||
return m_receive_buffer->used_bytes() > 0;
|
||||
}
|
||||
|
||||
KResultOr<size_t> VirtIOConsole::read(FileDescription&, u64, [[maybe_unused]] UserOrKernelBuffer& data, size_t)
|
||||
KResultOr<size_t> VirtIOConsole::read(FileDescription& desc, u64, UserOrKernelBuffer& buffer, size_t size)
|
||||
{
|
||||
return ENOTSUP;
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
if (!can_read(desc, size))
|
||||
return EAGAIN;
|
||||
|
||||
ScopedSpinLock ringbuffer_lock(m_receive_buffer->lock());
|
||||
|
||||
auto bytes_copied = m_receive_buffer->copy_data_out(size, buffer);
|
||||
m_receive_buffer->reclaim_space(m_receive_buffer->start_of_used(), bytes_copied.value());
|
||||
|
||||
return bytes_copied;
|
||||
}
|
||||
|
||||
bool VirtIOConsole::can_write(const FileDescription&, size_t) const
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue