1 /*
2 * Copyright (c) 2025 Antmicro <www.antmicro.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT virtio_console
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/virtio.h>
10 #include <zephyr/drivers/virtio/virtqueue.h>
11 #include <zephyr/spinlock.h>
12 #include <zephyr/drivers/uart.h>
13 #include <zephyr/sys/atomic.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(virtio_console, CONFIG_UART_LOG_LEVEL);
17
18 struct virtconsole_config {
19 const struct device *vdev;
20 };
21
22 struct _virtio_console_config {
23 uint16_t cols;
24 uint16_t rows;
25 uint32_t max_nr_ports;
26 uint32_t emerg_wr;
27 };
28 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
29 struct _virtio_console_control {
30 uint32_t port;
31 uint16_t event;
32 uint16_t value;
33 /* Device can give human-readable names to ports by sending */
34 /* VIRTIO_CONSOLE_PORT_NAME immediately followed by a name */
35 char name[CONFIG_UART_VIRTIO_CONSOLE_NAME_BUFSIZE];
36 };
37 struct _fifo_item_virtio_console_control {
38 void *fifo_reserved;
39 bool pending; /* true if message is awaiting transmission */
40 struct _virtio_console_control msg;
41 };
42 #endif
43
44 enum _flags {
45 RX_IRQ_ENABLED
46 };
47
48 enum _virtio_feature_bits {
49 VIRTIO_CONSOLE_F_SIZE,
50 VIRTIO_CONSOLE_F_MULTIPORT,
51 VIRTIO_CONSOLE_F_EMERG_WRITE
52 };
53
54 /* Virtqueues frequently used explicitly */
55 enum _named_virtqueues {
56 VIRTQ_RX,
57 VIRTQ_TX,
58 VIRTQ_CONTROL_RX,
59 VIRTQ_CONTROL_TX
60 };
61 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
62 enum _virtio_ctl_events {
63 VIRTIO_CONSOLE_DEVICE_READY,
64 VIRTIO_CONSOLE_DEVICE_ADD,
65 VIRTIO_CONSOLE_DEVICE_REMOVE,
66 VIRTIO_CONSOLE_PORT_READY,
67 VIRTIO_CONSOLE_CONSOLE_PORT,
68 VIRTIO_CONSOLE_RESIZE,
69 VIRTIO_CONSOLE_PORT_OPEN,
70 VIRTIO_CONSOLE_PORT_NAME
71 };
72
73 struct _ctl_cb_data {
74 struct virtconsole_data *data;
75 int buf_no;
76 };
77 #endif
78
79 /* This should be enough as QEMU only allows 31 */
80 #define VIRTIO_CONSOLE_MAX_PORTS 32
81
82 /* Allows virtconsole_recv_cb to know which virtqueue it was called by */
83 struct _rx_cb_data {
84 struct virtconsole_data *data;
85 uint16_t port;
86 };
87
88 /* Convert port numbers to virtqueue indices */
89 #define PORT_TO_RX_VQ_IDX(p) ((p) ? ((p + 1) * 2) : (VIRTQ_RX))
90 #define PORT_TO_TX_VQ_IDX(p) (PORT_TO_RX_VQ_IDX(p) + 1)
91
92 /* Convert virtqueue index to port number */
vq_idx_to_port(uint16_t q)93 static int8_t vq_idx_to_port(uint16_t q)
94 {
95 if (q % 2) { /* transmit queue (odd-numbered) */
96 if (q == VIRTQ_TX) {
97 return 0;
98 } else if (q != VIRTQ_CONTROL_TX) {
99 return (q / 2) - 1;
100 }
101 } else { /* receive queue (even-numbered) */
102 if (q == VIRTQ_RX) {
103 return 0;
104 } else if (q != VIRTQ_CONTROL_RX) {
105 return (q / 2) - 1;
106 }
107 }
108 return -1; /* control queues are not assigned to any port */
109 }
110
111 struct virtconsole_data {
112 const struct device *dev;
113 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
114 /* bitmask of ports to be used as console */
115 uint32_t console_ports;
116 int8_t n_console_ports;
117 size_t txctlcurrent;
118 struct _virtio_console_control rx_ctlbuf[CONFIG_UART_VIRTIO_CONSOLE_RX_CONTROL_BUFSIZE];
119 struct _fifo_item_virtio_console_control
120 tx_ctlbuf[CONFIG_UART_VIRTIO_CONSOLE_TX_CONTROL_BUFSIZE];
121 struct k_fifo tx_ctlfifo;
122 struct _ctl_cb_data ctl_cb_data[CONFIG_UART_VIRTIO_CONSOLE_RX_CONTROL_BUFSIZE];
123 struct _rx_cb_data rx_cb_data[VIRTIO_CONSOLE_MAX_PORTS];
124 #else
125 struct _rx_cb_data rx_cb_data[1];
126 #endif
127 struct k_spinlock txsl;
128 char rxbuf[CONFIG_UART_VIRTIO_CONSOLE_RX_BUFSIZE],
129 txbuf[CONFIG_UART_VIRTIO_CONSOLE_TX_BUFSIZE];
130 atomic_t flags;
131 atomic_t rx_started, rx_ready;
132 size_t rxcurrent, txcurrent;
133 uart_irq_callback_user_data_t irq_cb;
134 void *irq_cb_data;
135 struct _virtio_console_config *virtio_devcfg;
136 };
137
138 /* Return desired size for given virtqueue */
virtconsole_enum_queues_cb(uint16_t q_index,uint16_t q_size_max,void *)139 static uint16_t virtconsole_enum_queues_cb(uint16_t q_index, uint16_t q_size_max, void *)
140 {
141 switch (q_index) {
142 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
143 case VIRTQ_CONTROL_RX:
144 return CONFIG_UART_VIRTIO_CONSOLE_RX_CONTROL_BUFSIZE;
145 case VIRTQ_CONTROL_TX:
146 return CONFIG_UART_VIRTIO_CONSOLE_TX_CONTROL_BUFSIZE;
147 #endif
148 default:
149 return 1;
150 }
151 }
152
virtconsole_recv_cb(void * priv,uint32_t len)153 static void virtconsole_recv_cb(void *priv, uint32_t len)
154 {
155 struct _rx_cb_data *cbdata = priv;
156 struct virtconsole_data *data = cbdata->data;
157
158 atomic_set_bit(&(data->rx_ready), cbdata->port);
159 if (atomic_test_bit(&data->flags, RX_IRQ_ENABLED) && data->irq_cb) {
160 data->irq_cb(data->dev, data->irq_cb_data);
161 }
162 }
163
virtconsole_recv_setup(const struct device * dev,uint16_t q_no,void * addr,uint32_t len,void (* recv_cb)(void *,uint32_t),void * cb_data)164 static void virtconsole_recv_setup(const struct device *dev, uint16_t q_no, void *addr,
165 uint32_t len, void (*recv_cb)(void *, uint32_t), void *cb_data)
166 {
167 if (q_no % 2) {
168 return; /* This should not be called on tx queues (odd-numbered) */
169 }
170 const struct virtconsole_config *config = dev->config;
171 struct virtconsole_data *data = dev->data;
172
173 int port = vq_idx_to_port(q_no);
174
175 if ((port >= 0) && (port < VIRTIO_CONSOLE_MAX_PORTS)) {
176 atomic_set_bit(&(data->rx_started), port);
177 }
178 struct virtq *vq = virtio_get_virtqueue(config->vdev, q_no);
179
180 if (vq == NULL) {
181 LOG_ERR("could not access virtqueue %u", q_no);
182 return;
183 }
184 struct virtq_buf vqbuf[] = {{.addr = addr, .len = len}};
185
186 if (virtq_add_buffer_chain(vq, vqbuf, 1, 0, recv_cb, cb_data, K_NO_WAIT)) {
187 LOG_ERR("could not set up virtqueue %u for receiving", q_no);
188 return;
189 }
190 virtio_notify_virtqueue(config->vdev, q_no);
191 }
192 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
virtconsole_control_tx_flush(void * priv,uint32_t len)193 static void virtconsole_control_tx_flush(void *priv, uint32_t len)
194 {
195 struct virtconsole_data *data = priv;
196 const struct device *dev = data->dev;
197 const struct virtconsole_config *config = dev->config;
198 struct _fifo_item_virtio_console_control *item;
199 struct virtq *vq = virtio_get_virtqueue(config->vdev, VIRTQ_CONTROL_TX);
200
201 if (vq == NULL) {
202 LOG_ERR("could not access virtqueue 3");
203 return;
204 }
205 int i = vq->free_desc_n;
206
207 while ((i-- > 0) && (item = k_fifo_get(&data->tx_ctlfifo, K_NO_WAIT))) {
208 struct virtq_buf vqbuf = {.addr = &item->msg, .len = sizeof(item->msg)};
209
210 int ret = virtq_add_buffer_chain(vq, &vqbuf, 1, 1, virtconsole_control_tx_flush,
211 priv, K_NO_WAIT);
212
213 if (ret) {
214 LOG_ERR("could not send control message");
215 return;
216 }
217 virtio_notify_virtqueue(config->vdev, VIRTQ_CONTROL_TX);
218 item->pending = false;
219 }
220 }
221
virtconsole_send_control_msg(const struct device * dev,uint32_t port,uint16_t event,uint16_t value)222 static void virtconsole_send_control_msg(const struct device *dev, uint32_t port, uint16_t event,
223 uint16_t value)
224 {
225 const struct virtconsole_config *config = dev->config;
226 struct virtconsole_data *data = dev->data;
227
228 struct virtq *vq = virtio_get_virtqueue(config->vdev, VIRTQ_CONTROL_TX);
229
230 if (vq == NULL) {
231 LOG_ERR("could not access virtqueue 3");
232 return;
233 }
234 struct _fifo_item_virtio_console_control *item = &(data->tx_ctlbuf[data->txctlcurrent]);
235 struct _virtio_console_control *msg = &(item->msg);
236
237 if (item->pending) {
238 LOG_ERR("not enough free buffers for control message");
239 return;
240 }
241 msg->port = sys_cpu_to_le32(port);
242 msg->event = sys_cpu_to_le16(event);
243 msg->value = sys_cpu_to_le16(value);
244 struct virtq_buf vqbuf = {.addr = msg, .len = sizeof(*msg)};
245
246 int ret = virtq_add_buffer_chain(vq, &vqbuf, 1, 1, virtconsole_control_tx_flush, data,
247 K_NO_WAIT);
248
249 if (ret == -EBUSY) {
250 /* put in FIFO to be sent later, mark buffer as occupied to prevent overwriting */
251 k_fifo_put(&data->tx_ctlfifo, data->tx_ctlbuf + data->txctlcurrent);
252 item->pending = true;
253 } else if (ret == 0) {
254 virtio_notify_virtqueue(config->vdev, VIRTQ_CONTROL_TX);
255 } else {
256 LOG_ERR("could not send control message");
257 return;
258 }
259 data->txctlcurrent =
260 (data->txctlcurrent + 1) % CONFIG_UART_VIRTIO_CONSOLE_TX_CONTROL_BUFSIZE;
261 }
262
virtconsole_control_recv_cb(void * priv,uint32_t len)263 static void virtconsole_control_recv_cb(void *priv, uint32_t len)
264 {
265 struct _ctl_cb_data *ctld = priv;
266 struct virtconsole_data *data = ctld->data;
267
268 for (int i = 0; i < CONFIG_UART_VIRTIO_CONSOLE_RX_CONTROL_BUFSIZE; i++) {
269 if (data->rx_ctlbuf[i].port == UINT32_MAX) {
270 continue;
271 }
272 data->rx_ctlbuf[i].port = sys_le32_to_cpu(data->rx_ctlbuf[i].port);
273 data->rx_ctlbuf[i].event = sys_le16_to_cpu(data->rx_ctlbuf[i].event);
274 data->rx_ctlbuf[i].value = sys_le16_to_cpu(data->rx_ctlbuf[i].value);
275
276 switch (data->rx_ctlbuf[i].event) {
277 case VIRTIO_CONSOLE_DEVICE_ADD:
278 virtconsole_send_control_msg(
279 data->dev, data->rx_ctlbuf[i].port, VIRTIO_CONSOLE_PORT_READY,
280 (data->rx_ctlbuf[i].port) < VIRTIO_CONSOLE_MAX_PORTS);
281 break;
282 case VIRTIO_CONSOLE_DEVICE_REMOVE: {
283 int port = data->rx_ctlbuf[i].port;
284
285 if ((port < VIRTIO_CONSOLE_MAX_PORTS) &&
286 IS_BIT_SET(data->console_ports, port)) {
287 /* Remove console port (unset bit) */
288 data->console_ports = ~(data->console_ports);
289 data->console_ports |= BIT(port);
290 data->console_ports = ~(data->console_ports);
291 data->n_console_ports--;
292 }
293 break;
294 }
295 case VIRTIO_CONSOLE_CONSOLE_PORT: {
296 int port = data->rx_ctlbuf[i].port;
297
298 if ((port < VIRTIO_CONSOLE_MAX_PORTS) &&
299 !IS_BIT_SET(data->console_ports, port)) {
300 data->console_ports |= BIT(port);
301 data->n_console_ports++;
302 }
303 virtconsole_send_control_msg(data->dev, data->rx_ctlbuf[i].port,
304 VIRTIO_CONSOLE_PORT_OPEN, 1);
305
306 if (atomic_test_bit(&data->flags, RX_IRQ_ENABLED)) {
307 if (!atomic_test_bit(&(data->rx_started), port)) {
308 uint16_t q_no = PORT_TO_RX_VQ_IDX(port);
309
310 virtconsole_recv_setup(data->dev, q_no,
311 data->rxbuf + data->rxcurrent,
312 sizeof(char), virtconsole_recv_cb,
313 data->rx_cb_data + port);
314 }
315 }
316 break;
317 }
318 case VIRTIO_CONSOLE_RESIZE:
319 /* Terminal sizes are not supported by Zephyr and the */
320 /* VIRTIO_CONSOLE_F_SIZE feature was not enabled */
321 LOG_WRN("device tried to set console size");
322 break;
323 case VIRTIO_CONSOLE_PORT_OPEN:
324 LOG_INF("port %u is ready", data->rx_ctlbuf[i].port);
325 break;
326 case VIRTIO_CONSOLE_PORT_NAME:
327 LOG_INF("port %u is named \"%.*s\"", data->rx_ctlbuf[i].port,
328 (int)ARRAY_SIZE(data->rx_ctlbuf[i].name), data->rx_ctlbuf[i].name);
329 break;
330 default:
331 break;
332 }
333 data->rx_ctlbuf[i].port = UINT32_MAX;
334 memset(&(data->rx_ctlbuf[i].name), 0, ARRAY_SIZE(data->rx_ctlbuf[i].name));
335 }
336 virtconsole_recv_setup(data->dev, VIRTQ_CONTROL_RX, &data->rx_ctlbuf[ctld->buf_no],
337 sizeof(struct _virtio_console_control), virtconsole_control_recv_cb,
338 ctld);
339 }
340 #endif
virtconsole_poll_in(const struct device * dev,unsigned char * c)341 static int virtconsole_poll_in(const struct device *dev, unsigned char *c)
342 {
343 struct virtconsole_data *data = dev->data;
344 int ready = -1;
345 int port = 0;
346
347 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
348 int n_ports_checked = 0;
349
350 for (; port < VIRTIO_CONSOLE_MAX_PORTS; port++) {
351 if (!IS_BIT_SET(data->console_ports, port)) {
352 continue;
353 }
354 #endif
355 uint16_t q_no = PORT_TO_RX_VQ_IDX(port);
356
357 if (!atomic_test_bit(&(data->rx_started), port)) {
358 virtconsole_recv_setup(dev, q_no, data->rxbuf + data->rxcurrent,
359 sizeof(char), virtconsole_recv_cb,
360 data->rx_cb_data + port);
361 }
362 if (atomic_test_and_clear_bit(&(data->rx_ready), port)) {
363 ready = q_no;
364 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
365 break;
366 #endif
367 }
368 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
369 if ((++n_ports_checked) >= data->n_console_ports) {
370 break;
371 }
372 }
373 #endif
374 if (ready == -1) {
375 return -1;
376 }
377 if (c) {
378 *c = data->rxbuf[data->rxcurrent];
379 }
380 data->rxcurrent = (data->rxcurrent + 1) % CONFIG_UART_VIRTIO_CONSOLE_RX_BUFSIZE;
381 virtconsole_recv_setup(dev, ready, data->rxbuf + data->rxcurrent, sizeof(char),
382 virtconsole_recv_cb, data->rx_cb_data + port);
383 return 0;
384 }
385
virtconsole_poll_out(const struct device * dev,unsigned char c)386 static void virtconsole_poll_out(const struct device *dev, unsigned char c)
387 {
388 const struct virtconsole_config *config = dev->config;
389 struct virtconsole_data *data = dev->data;
390
391 K_SPINLOCK(&(data->txsl)) {
392 int port = 0;
393
394 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
395 int n_ports_checked = 0;
396
397 for (; port < VIRTIO_CONSOLE_MAX_PORTS; port++) {
398 if (!IS_BIT_SET(data->console_ports, port)) {
399 continue;
400 }
401 #endif
402 uint16_t q_no = PORT_TO_TX_VQ_IDX(port);
403 struct virtq *vq = virtio_get_virtqueue(config->vdev, q_no);
404
405 if (vq == NULL) {
406 LOG_ERR("could not access virtqueue %u", q_no);
407 K_SPINLOCK_BREAK;
408 }
409 data->txbuf[data->txcurrent] = c;
410 struct virtq_buf vqbuf = {.addr = data->txbuf + data->txcurrent,
411 .len = sizeof(char)};
412
413 if (virtq_add_buffer_chain(vq, &vqbuf, 1, 1, NULL, NULL, K_FOREVER)) {
414 LOG_ERR("could not send character");
415 K_SPINLOCK_BREAK;
416 }
417 virtio_notify_virtqueue(config->vdev, q_no);
418 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
419 if ((++n_ports_checked) >= data->n_console_ports) {
420 break;
421 }
422 }
423 #endif
424 data->txcurrent = (data->txcurrent + 1) % CONFIG_UART_VIRTIO_CONSOLE_TX_BUFSIZE;
425 }
426 }
427
428 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
virtconsole_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)429 static int virtconsole_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
430 {
431 int i = 0;
432
433 for (; i < size; i++) {
434 virtconsole_poll_out(dev, tx_data[i]);
435 }
436 return i;
437 }
virtconsole_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)438 static int virtconsole_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
439 {
440 int i = 0;
441
442 for (; i < size; i++) {
443 if (virtconsole_poll_in(dev, rx_data + i) == -1) {
444 break;
445 }
446 }
447 return i;
448 }
virtconsole_irq_tx_enable(const struct device * dev)449 static void virtconsole_irq_tx_enable(const struct device *dev)
450 {
451 /* Only need to invoke the callback */
452 struct virtconsole_data *data = dev->data;
453
454 if (data->irq_cb) {
455 data->irq_cb(dev, data->irq_cb_data);
456 }
457 }
virtconsole_irq_tx_ready(const struct device * dev)458 static int virtconsole_irq_tx_ready(const struct device *dev)
459 {
460 /* Always ready to transmit characters, nothing to wait for */
461 return 1;
462 }
virtconsole_irq_tx_complete(const struct device * dev)463 static int virtconsole_irq_tx_complete(const struct device *dev)
464 {
465 /* Always complete, nothing to wait for */
466 return 1;
467 }
virtconsole_irq_rx_enable(const struct device * dev)468 static void virtconsole_irq_rx_enable(const struct device *dev)
469 {
470 struct virtconsole_data *data = dev->data;
471
472 /* Start receiving characters immediately */
473 virtconsole_poll_in(dev, NULL);
474 atomic_set_bit(&data->flags, RX_IRQ_ENABLED);
475 if (data->irq_cb) {
476 data->irq_cb(dev, data->irq_cb_data);
477 }
478 }
virtconsole_irq_rx_ready(const struct device * dev)479 static int virtconsole_irq_rx_ready(const struct device *dev)
480 {
481 struct virtconsole_data *data = dev->data;
482
483 /* True if any port has characters ready to read */
484 return atomic_get(&(data->rx_ready));
485 }
virtconsole_irq_is_pending(const struct device * dev)486 static int virtconsole_irq_is_pending(const struct device *dev)
487 {
488 return virtconsole_irq_rx_ready(dev);
489 }
virtconsole_irq_update(const struct device * dev)490 static int virtconsole_irq_update(const struct device *dev)
491 {
492 /* Nothing to be done */
493 return 1;
494 }
virtconsole_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * user_data)495 static void virtconsole_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
496 void *user_data)
497 {
498 struct virtconsole_data *data = dev->data;
499
500 data->irq_cb = cb;
501 data->irq_cb_data = user_data;
502 }
503 #endif
504
virtconsole_init(const struct device * dev)505 static int virtconsole_init(const struct device *dev)
506 {
507 const struct virtconsole_config *config = dev->config;
508 struct virtconsole_data *data = dev->data;
509
510 data->dev = dev;
511 for (int i = 0; i < ARRAY_SIZE(data->rx_cb_data); i++) {
512 data->rx_cb_data[i].data = data;
513 data->rx_cb_data[i].port = i;
514 }
515 size_t n_queues = 2;
516
517 __maybe_unused bool multiport =
518 virtio_read_device_feature_bit(config->vdev, VIRTIO_CONSOLE_F_MULTIPORT);
519
520 data->virtio_devcfg = virtio_get_device_specific_config(config->vdev);
521
522 if (data->virtio_devcfg == NULL) {
523 LOG_WRN("could not get device-specific config");
524 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
525 LOG_WRN("disabling multiport feature");
526 multiport = false;
527 #endif
528 }
529 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
530 if (multiport) {
531 if (virtio_write_driver_feature_bit(config->vdev, VIRTIO_CONSOLE_F_MULTIPORT, 1)) {
532 multiport = false;
533 LOG_WRN("could not enable multiport feature");
534 }
535 if (virtio_commit_feature_bits(config->vdev)) {
536 multiport = false;
537 LOG_WRN("could not commit feature bits; disabling multiport feature");
538 } else {
539 n_queues = (sys_le16_to_cpu(data->virtio_devcfg->max_nr_ports) + 1) * 2;
540 }
541 }
542 if (!multiport) {
543 /* If the multiport feature is off, use the default */
544 data->n_console_ports = 1;
545 data->console_ports = 1; /* Enable port 0 */
546 }
547 #endif
548 int ret = virtio_init_virtqueues(config->vdev, n_queues, virtconsole_enum_queues_cb, NULL);
549
550 if (ret) {
551 LOG_ERR("error initializing virtqueues!");
552 return ret;
553 }
554 virtio_finalize_init(config->vdev);
555 #ifdef CONFIG_UART_VIRTIO_CONSOLE_F_MULTIPORT
556 if (multiport) {
557 k_fifo_init(&data->tx_ctlfifo);
558 for (int i = 0; i < CONFIG_UART_VIRTIO_CONSOLE_RX_CONTROL_BUFSIZE; i++) {
559 data->ctl_cb_data[i].data = data;
560 data->ctl_cb_data[i].buf_no = i;
561 data->rx_ctlbuf[i].port = UINT32_MAX;
562 virtconsole_recv_setup(data->dev, VIRTQ_CONTROL_RX, &data->rx_ctlbuf[i],
563 sizeof(struct _virtio_console_control),
564 virtconsole_control_recv_cb, &data->ctl_cb_data[i]);
565 }
566 virtconsole_send_control_msg(dev, 0, VIRTIO_CONSOLE_DEVICE_READY, 1);
567 }
568 #endif
569 return 0;
570 }
571
572 static DEVICE_API(uart, virtconsole_api) = {
573 .poll_in = virtconsole_poll_in,
574 .poll_out = virtconsole_poll_out,
575 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
576 .fifo_fill = virtconsole_fifo_fill,
577 .fifo_read = virtconsole_fifo_read,
578 .irq_tx_enable = virtconsole_irq_tx_enable,
579 .irq_tx_ready = virtconsole_irq_tx_ready,
580 .irq_tx_complete = virtconsole_irq_tx_complete,
581 .irq_rx_enable = virtconsole_irq_rx_enable,
582 .irq_rx_ready = virtconsole_irq_rx_ready,
583 .irq_is_pending = virtconsole_irq_is_pending,
584 .irq_update = virtconsole_irq_update,
585 .irq_callback_set = virtconsole_irq_callback_set,
586 #endif
587 };
588
589 #define VIRTIO_CONSOLE_DEFINE(inst) \
590 static struct virtconsole_data virtconsole_data_##inst; \
591 static const struct virtconsole_config virtconsole_config_##inst = { \
592 .vdev = DEVICE_DT_GET(DT_PARENT(DT_DRV_INST(inst))), \
593 }; \
594 DEVICE_DT_INST_DEFINE(inst, virtconsole_init, NULL, &virtconsole_data_##inst, \
595 &virtconsole_config_##inst, POST_KERNEL, \
596 CONFIG_SERIAL_INIT_PRIORITY, &virtconsole_api);
597
598 DT_INST_FOREACH_STATUS_OKAY(VIRTIO_CONSOLE_DEFINE)
599