1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #pragma once
5 
6 #include "device.h"
7 #include "ring.h"
8 
9 #include <ddk/device.h>
10 #include <fbl/array.h>
11 #include <fbl/intrusive_double_list.h>
12 #include <zircon/thread_annotations.h>
13 
14 namespace virtio {
15 
16 // Describes a chunk of memory used for data transfers between the device and the driver,
17 // points to the memory inside TransferBuffer below
18 struct TransferDescriptor : fbl::DoublyLinkedListable<TransferDescriptor*> {
19     uint8_t* virt;
20     uintptr_t phys;
21     uint32_t total_len;
22     uint32_t used_len;
23     uint32_t processed_len;
24 };
25 
26 // Manages memory we use for transfers, TransferDescriptor points to the memory inside the class
27 class TransferBuffer {
28 public:
29     TransferBuffer();
30     ~TransferBuffer();
31 
32     zx_status_t Init(const zx::bti& bti, size_t count, uint32_t chunk_size);
33 
34     TransferDescriptor* GetDescriptor(size_t index);
35     TransferDescriptor* PhysicalToDescriptor(uintptr_t phys);
36 
37 private:
38     size_t count_ = 0;
39     size_t size_ = 0;
40     uint32_t chunk_size_ = 0;
41 
42     io_buffer_t buf_;
43     fbl::Array<TransferDescriptor> descriptor_;
44 };
45 
46 // Just a list of descriptors
47 class TransferQueue {
48 public:
49     void Add(TransferDescriptor* desc);
50     TransferDescriptor* Peek();
51     TransferDescriptor* Dequeue();
52     bool IsEmpty() const;
53 
54 private:
55     fbl::DoublyLinkedList<TransferDescriptor*> queue_;
56 };
57 
58 // Actual virtio console implementation
59 class ConsoleDevice : public Device {
60 public:
61     explicit ConsoleDevice(zx_device_t* device, zx::bti bti, fbl::unique_ptr<Backend> backend);
62     virtual ~ConsoleDevice();
63 
64     virtual zx_status_t Init() override;
65 
66     virtual void IrqRingUpdate() override;
IrqConfigChange()67     virtual void IrqConfigChange() override {}; // No need to handle configuration changes
tag()68     const char* tag() const override { return "virtio-console"; };
69 
70 private:
71     // For two queues it sums up to 32KiB, we probably don't need that much
72     constexpr static size_t kDescriptors = 32;
73     constexpr static uint32_t kChunkSize = 512;
74 
75     static zx_status_t virtio_console_read(void* ctx, void* buf, size_t len, zx_off_t off, size_t* actual);
76     static zx_status_t virtio_console_write(void* ctx, const void* buf, size_t len, zx_off_t off, size_t* actual);
77 
78     zx_status_t Read(void* buf, size_t len, zx_off_t off, size_t* actual);
79     zx_status_t Write(const void* buf, size_t len, zx_off_t off, size_t* actual);
80 
81     fbl::Mutex request_lock_;
82 
83     TransferBuffer port0_receive_buffer_ TA_GUARDED(request_lock_);
84     TransferQueue port0_receive_descriptors_ TA_GUARDED(request_lock_);
85     Ring port0_receive_queue_ TA_GUARDED(request_lock_) = {this};
86 
87     TransferBuffer port0_transmit_buffer_ TA_GUARDED(request_lock_);
88     TransferQueue port0_transmit_descriptors_ TA_GUARDED(request_lock_);
89     Ring port0_transmit_queue_ TA_GUARDED(request_lock_) = {this};
90 };
91 
92 } // namespace virtio
93