forked from includeos/IncludeOS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconsole.cpp
More file actions
174 lines (139 loc) · 4.63 KB
/
console.cpp
File metadata and controls
174 lines (139 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#define DEBUG
#define DEBUG2
#include <virtio/console.hpp>
#include <kernel/irq_manager.hpp>
#include <hw/pci.hpp>
#include <cassert>
#include <cstring>
extern "C"
{ void panic(const char*); }
#define VIRTIO_CONSOLE_F_SIZE 0
#define VIRTIO_CONSOLE_F_MULTIPORT 1
#define VIRTIO_CONSOLE_F_EMERG_WRITE 2
#define VIRTIO_CONSOLE_DEVICE_READY 0
#define VIRTIO_CONSOLE_DEVICE_ADD 1
#define VIRTIO_CONSOLE_DEVICE_REMOVE 2
#define VIRTIO_CONSOLE_PORT_READY 3
#define VIRTIO_CONSOLE_CONSOLE_PORT 4
#define VIRTIO_CONSOLE_RESIZE 5
#define VIRTIO_CONSOLE_PORT_OPEN 6
#define VIRTIO_CONSOLE_PORT_NAME 7
#define FEAT(x) (1 << x)
VirtioCon::VirtioCon(hw::PCI_Device& d)
: Virtio(d),
rx(queue_size(0), 0, iobase()),
tx(queue_size(1), 1, iobase()),
ctl_rx(queue_size(2), 2, iobase()),
ctl_tx(queue_size(3), 3, iobase())
{
INFO("VirtioCon", "Driver initializing");
uint32_t needed_features =
FEAT(VIRTIO_CONSOLE_F_MULTIPORT);
negotiate_features(needed_features);
CHECK(features() & FEAT(VIRTIO_CONSOLE_F_SIZE),
"Valid console dimensions");
CHECK(features() & FEAT(VIRTIO_CONSOLE_F_MULTIPORT),
"Multiple ports support");
CHECK(features() & FEAT(VIRTIO_CONSOLE_F_EMERG_WRITE),
"Emergency write support");
CHECK ((features() & needed_features) == needed_features,
"Negotiated needed features");
// Step 1 - Initialize queues
auto success = assign_queue(0, (uint32_t) rx.queue_desc());
CHECK(success, "Receive queue assigned (0x%x) to device",
(uint32_t) rx.queue_desc());
success = assign_queue(1, (uint32_t) tx.queue_desc());
CHECK(success, "Transmit queue assigned (0x%x) to device",
(uint32_t) tx.queue_desc());
success = assign_queue(2, (uint32_t) ctl_rx.queue_desc());
CHECK(success, "Control rx queue assigned (0x%x) to device",
(uint32_t) ctl_rx.queue_desc());
success = assign_queue(3, (uint32_t) ctl_tx.queue_desc());
CHECK(success, "Control tx queue assigned (0x%x) to device",
(uint32_t) ctl_tx.queue_desc());
/*
success = assign_queue(4, (uint32_t) rx1.queue_desc());
CHECK(success, "rx1 queue assigned (0x%x) to device",
(uint32_t) rx1.queue_desc());
success = assign_queue(5, (uint32_t) tx1.queue_desc());
CHECK(success, "tx1 queue assigned (0x%x) to device",
(uint32_t) tx1.queue_desc());
*/
// Step 3 - Fill receive queue with buffers
INFO("VirtioCon", "Queue size rx: %d tx: %d\n",
rx.size(), tx.size());
// Get device configuration
get_config();
// Signal setup complete.
setup_complete((features() & needed_features) == needed_features);
CHECK((features() & needed_features) == needed_features, "Signalled driver OK");
// Hook up IRQ handler (inherited from Virtio)
auto del(delegate<void()>{this, &VirtioCon::irq_handler});
IRQ_manager::subscribe(irq(), del);
IRQ_manager::enable_irq(irq());
// Done
INFO("VirtioCon", "Console with size (%u, %u), %u ports",
config.cols, config.rows, config.max_nr_ports);
rx.kick();
}
void VirtioCon::get_config()
{
Virtio::get_config(&config, sizeof(console_config));
}
void VirtioCon::irq_handler()
{
debug2("<VirtioCon> IRQ handler\n");
//Virtio Std. § 4.1.5.5, steps 1-3
// Step 1. read ISR
unsigned char isr = hw::inp(iobase() + VIRTIO_PCI_ISR);
// Step 2. A) - one of the queues have changed
if (isr & 1)
{
// This now means service RX & TX interchangeably
service_RX();
}
// Step 2. B)
if (isr & 2)
{
debug("\t <VirtioCon> Configuration change:\n");
//debug("\t Old status: 0x%x\n", config.status);
get_config();
//debug("\t New status: 0x%x \n", config.status);
}
IRQ_manager::eoi(irq());
}
void VirtioCon::service_RX()
{
rx.disable_interrupts();
while (rx.new_incoming())
{
uint32_t len = 0;
char* condata = (char*) rx.dequeue(&len);
uint32_t dontcare;
rx.dequeue(&dontcare);
if (condata)
{
//printf("service_RX() received %u bytes from virtio console\n", len);
//printf("Data: %s\n", condata);
//vbr->handler(0, vbr->sector);
}
else
{
// acknowledgement
//printf("No data, just len = %d\n", len);
}
}
rx.enable_interrupts();
}
void VirtioCon::write (
const void* data,
size_t len)
{
char* heapdata = new char[len];
memcpy(heapdata, data, len);
scatterlist sg[1];
sg[0].data = (void*) heapdata;
sg[0].size = len; // +1?
tx.enqueue(sg, 1, 0, (void*) data);
tx.kick();
}