blob: cfa153556b21cdbaa5c65423904f40214dff6d50 [file] [log] [blame]
// Copyright 2016 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.
#pragma once
#include "device.h"
#include "ring.h"
#include <ddk/device.h>
#include <fbl/array.h>
#include <fbl/intrusive_double_list.h>
#include <zircon/thread_annotations.h>
namespace virtio {
// Describes a chunk of memory used for data transfers between the device and the driver,
// points to the memory inside TransferBuffer below
struct TransferDescriptor : fbl::DoublyLinkedListable<TransferDescriptor*> {
uint8_t* virt;
uintptr_t phys;
uint32_t total_len;
uint32_t used_len;
uint32_t processed_len;
};
// Manages memory we use for transfers, TransferDescriptor points to the memory inside the class
class TransferBuffer {
public:
TransferBuffer();
~TransferBuffer();
zx_status_t Init(const zx::bti& bti, size_t count, uint32_t chunk_size);
TransferDescriptor* GetDescriptor(size_t index);
TransferDescriptor* PhysicalToDescriptor(uintptr_t phys);
private:
size_t count_ = 0;
size_t size_ = 0;
uint32_t chunk_size_ = 0;
io_buffer_t buf_;
fbl::Array<TransferDescriptor> descriptor_;
};
// Just a list of descriptors
class TransferQueue {
public:
void Add(TransferDescriptor* desc);
TransferDescriptor* Peek();
TransferDescriptor* Dequeue();
bool IsEmpty() const;
private:
fbl::DoublyLinkedList<TransferDescriptor*> queue_;
};
// Actual virtio console implementation
class ConsoleDevice : public Device {
public:
explicit ConsoleDevice(zx_device_t* device, zx::bti bti, fbl::unique_ptr<Backend> backend);
virtual ~ConsoleDevice();
virtual zx_status_t Init() override;
virtual void IrqRingUpdate() override;
virtual void IrqConfigChange() override {}; // No need to handle configuration changes
const char* tag() const override { return "virtio-console"; };
private:
// For two queues it sums up to 32KiB, we probably don't need that much
constexpr static size_t kDescriptors = 32;
constexpr static uint32_t kChunkSize = 512;
static zx_status_t virtio_console_read(void* ctx, void* buf, size_t len, zx_off_t off, size_t* actual);
static zx_status_t virtio_console_write(void* ctx, const void* buf, size_t len, zx_off_t off, size_t* actual);
zx_status_t Read(void* buf, size_t len, zx_off_t off, size_t* actual);
zx_status_t Write(const void* buf, size_t len, zx_off_t off, size_t* actual);
fbl::Mutex request_lock_;
TransferBuffer port0_receive_buffer_ TA_GUARDED(request_lock_);
TransferQueue port0_receive_descriptors_ TA_GUARDED(request_lock_);
Ring port0_receive_queue_ TA_GUARDED(request_lock_) = {this};
TransferBuffer port0_transmit_buffer_ TA_GUARDED(request_lock_);
TransferQueue port0_transmit_descriptors_ TA_GUARDED(request_lock_);
Ring port0_transmit_queue_ TA_GUARDED(request_lock_) = {this};
};
} // namespace virtio