123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
- #include <rthw.h>
- #include <rtthread.h>
- #include <cpuport.h>
- #ifdef RT_USING_VIRTIO_CONSOLE
- #include <virtio_console.h>
- struct port_device
- {
- struct rt_device parent;
- rt_list_t node;
- rt_uint32_t port_id;
- rt_bool_t rx_notify;
- rt_bool_t need_destroy;
- struct virtio_console_device *console;
- struct virtq *queue_rx, *queue_tx;
- rt_uint32_t queue_rx_index, queue_tx_index;
- #ifdef RT_USING_SMP
- struct rt_spinlock spinlock_rx, spinlock_tx;
- #endif
- struct rt_device_notify rx_notify_helper;
- struct
- {
- char rx_char, tx_char;
- } info[VIRTIO_CONSOLE_QUEUE_SIZE];
- };
- static void virtio_console_send_ctrl(struct virtio_console_device *virtio_console_dev,
- struct virtio_console_control *ctrl)
- {
- rt_uint16_t id;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
- struct virtq *queue_ctrl_tx;
- #ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
- #endif
- queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
- id = queue_ctrl_tx->avail->idx % queue_ctrl_tx->num;
- rt_memcpy(&virtio_console_dev->info[id].tx_ctrl, ctrl, sizeof(struct virtio_console_control));
- virtio_free_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
- virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id,
- virtio_console_dev->info[id].tx_ctrl_paddr, sizeof(struct virtio_console_control), 0, 0);
- virtio_submit_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
- virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
- virtio_alloc_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
- #endif
- }
- static rt_err_t virtio_console_port_init(rt_device_t dev);
- static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag);
- static rt_err_t virtio_console_port_close(rt_device_t dev);
- static rt_ssize_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
- static rt_ssize_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
- static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args);
- #ifdef RT_USING_DEVICE_OPS
- const static struct rt_device_ops virtio_console_port_ops =
- {
- virtio_console_port_init,
- virtio_console_port_open,
- virtio_console_port_close,
- virtio_console_port_read,
- virtio_console_port_write,
- virtio_console_port_control
- };
- #endif
- static rt_err_t virtio_console_port_create(struct virtio_console_device *virtio_console_dev)
- {
- rt_uint32_t port_id;
- char dev_name[RT_NAME_MAX];
- struct port_device *port_dev, *prev_port_dev = RT_NULL;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
- if (virtio_console_dev->port_nr > 0 && !virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- return -RT_ENOSYS;
- }
- if (virtio_console_dev->port_nr >= virtio_console_dev->max_port_nr)
- {
- return -RT_EFULL;
- }
- port_id = 0;
- /* The port device list is always ordered, so just find next number for id */
- rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
- {
- if (port_dev->port_id != port_id)
- {
- break;
- }
- ++port_id;
- prev_port_dev = port_dev;
- }
- port_dev = rt_malloc(sizeof(struct port_device));
- if (port_dev == RT_NULL)
- {
- return -RT_ENOMEM;
- }
- port_dev->parent.type = RT_Device_Class_Char;
- #ifdef RT_USING_DEVICE_OPS
- port_dev->parent.ops = &virtio_console_port_ops;
- #else
- port_dev->parent.init = virtio_console_port_init;
- port_dev->parent.open = virtio_console_port_open;
- port_dev->parent.close = virtio_console_port_close;
- port_dev->parent.read = virtio_console_port_read;
- port_dev->parent.write = virtio_console_port_write;
- port_dev->parent.control = virtio_console_port_control;
- #endif
- port_dev->parent.rx_indicate = RT_NULL;
- port_dev->parent.tx_complete = RT_NULL;
- rt_list_init(&port_dev->node);
- port_dev->port_id = port_id;
- port_dev->need_destroy = RT_FALSE;
- port_dev->rx_notify = RT_TRUE;
- port_dev->console = virtio_console_dev;
- port_dev->queue_rx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
- port_dev->queue_tx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
- port_dev->queue_rx = &virtio_dev->queues[port_dev->queue_rx_index];
- port_dev->queue_tx = &virtio_dev->queues[port_dev->queue_tx_index];
- #ifdef RT_USING_SMP
- rt_spin_lock_init(&port_dev->spinlock_rx);
- rt_spin_lock_init(&port_dev->spinlock_tx);
- #endif
- rt_snprintf(dev_name, RT_NAME_MAX, "vport%dp%d", virtio_console_dev->console_id, port_id);
- if (rt_device_register((rt_device_t)port_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX) != RT_EOK)
- {
- rt_free(port_dev);
- return -RT_ERROR;
- }
- if (prev_port_dev != RT_NULL)
- {
- rt_list_insert_after(&prev_port_dev->node, &port_dev->node);
- }
- else
- {
- /* Port0 */
- rt_list_insert_after(&virtio_console_dev->port_head, &port_dev->node);
- }
- virtio_console_dev->port_nr++;
- return RT_EOK;
- }
- static void virtio_console_port_destroy(struct virtio_console_device *virtio_console_dev,
- struct port_device *port_dev)
- {
- struct virtio_console_control set_ctrl;
- set_ctrl.id = port_dev->port_id;
- set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
- set_ctrl.value = 0;
- virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
- virtio_console_dev->port_nr--;
- rt_list_remove(&port_dev->node);
- rt_device_unregister((rt_device_t)port_dev);
- rt_free(port_dev);
- }
- static rt_err_t virtio_console_port_init(rt_device_t dev)
- {
- rt_uint16_t id;
- rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
- rt_uint16_t rx_queue_index, tx_queue_index;
- struct port_device *port_dev = (struct port_device *)dev;
- struct virtio_console_device *virtio_console_dev = port_dev->console;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
- struct virtq *queue_rx, *queue_tx;
- rx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
- tx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
- queue_rx = &virtio_dev->queues[rx_queue_index];
- queue_tx = &virtio_dev->queues[tx_queue_index];
- virtio_alloc_desc_chain(virtio_dev, rx_queue_index, queue_rx->num, idx);
- virtio_alloc_desc_chain(virtio_dev, tx_queue_index, queue_tx->num, idx);
- for (id = 0; id < queue_rx->num; ++id)
- {
- void *addr = &port_dev->info[id].rx_char;
- virtio_fill_desc(virtio_dev, rx_queue_index, id,
- VIRTIO_VA2PA(addr), sizeof(char), VIRTQ_DESC_F_WRITE, 0);
- queue_rx->avail->ring[id] = id;
- }
- rt_hw_dsb();
- queue_rx->avail->flags = 0;
- queue_rx->avail->idx = queue_rx->num;
- queue_rx->used_idx = queue_rx->used->idx;
- queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
- queue_tx->avail->idx = 0;
- virtio_queue_notify(virtio_dev, rx_queue_index);
- if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- struct virtio_console_control set_ctrl;
- set_ctrl.id = VIRTIO_CONSOLE_PORT_BAD_ID;
- set_ctrl.event = VIRTIO_CONSOLE_DEVICE_READY;
- set_ctrl.value = 1;
- virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
- }
- return RT_EOK;
- }
- static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag)
- {
- struct port_device *port_dev = (struct port_device *)dev;
- if (port_dev->port_id == 0 && virtio_has_feature(&port_dev->console->virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- /* Port0 is reserve in multiport */
- return -RT_ERROR;
- }
- port_dev->rx_notify = RT_TRUE;
- return RT_EOK;
- }
- static rt_err_t virtio_console_port_close(rt_device_t dev)
- {
- struct port_device *port_dev = (struct port_device *)dev;
- if (port_dev->need_destroy)
- {
- virtio_console_port_destroy(port_dev->console, port_dev);
- /*
- * We released the device memory in virtio_console_port_destroy,
- * rt_device_close has not finished yet, make the return value
- * to empty so that rt_device_close will not access the device memory.
- */
- return -RT_EEMPTY;
- }
- port_dev->rx_notify = RT_FALSE;
- return RT_EOK;
- }
- static rt_ssize_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
- {
- rt_off_t i = 0;
- rt_uint16_t id;
- rt_uint32_t len;
- struct port_device *port_dev = (struct port_device *)dev;
- struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
- rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
- struct virtq *queue_rx = port_dev->queue_rx;
- #ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
- #endif
- while (i < size)
- {
- if (queue_rx->used_idx == queue_rx->used->idx)
- {
- break;
- }
- rt_hw_dsb();
- id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
- len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
- if (len > sizeof(char))
- {
- rt_kprintf("%s: Receive buffer's size = %u is too big!\n", port_dev->parent.parent.name, len);
- len = sizeof(char);
- }
- *((char *)buffer + i) = port_dev->info[id].rx_char;
- queue_rx->used_idx++;
- virtio_submit_chain(virtio_dev, queue_rx_index, id);
- virtio_queue_notify(virtio_dev, queue_rx_index);
- i += len;
- }
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
- #endif
- size = i;
- return size;
- }
- static rt_ssize_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
- {
- char ch = 0;
- rt_off_t i = 0;
- rt_uint16_t id;
- struct port_device *port_dev = (struct port_device *)dev;
- struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
- rt_uint32_t queue_tx_index = port_dev->queue_tx_index;
- struct virtq *queue_tx = port_dev->queue_tx;
- #ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_tx);
- #endif
- while (i < size || ch == '\r')
- {
- id = queue_tx->avail->idx % queue_tx->num;
- /* Keep the way until 'new line' are unified */
- if (ch != '\r')
- {
- ch = *((const char *)buffer + i);
- }
- else
- {
- i -= sizeof(char);
- }
- port_dev->info[id].tx_char = ch;
- ch = (ch == '\n' ? '\r' : 0);
- virtio_free_desc(virtio_dev, queue_tx_index, id);
- virtio_fill_desc(virtio_dev, queue_tx_index, id,
- VIRTIO_VA2PA(&port_dev->info[id].tx_char), sizeof(char), 0, 0);
- virtio_submit_chain(virtio_dev, queue_tx_index, id);
- virtio_queue_notify(virtio_dev, queue_tx_index);
- virtio_alloc_desc(virtio_dev, queue_tx_index);
- i += sizeof(char);
- }
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&port_dev->spinlock_tx, level);
- #endif
- return size;
- }
- static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args)
- {
- rt_err_t status = RT_EOK;
- struct port_device *port_dev = (struct port_device *)dev;
- switch (cmd)
- {
- case RT_DEVICE_CTRL_NOTIFY_SET:
- if (args == RT_NULL)
- {
- status = -RT_ERROR;
- break;
- }
- rt_memcpy(&port_dev->rx_notify_helper, args, sizeof(port_dev->rx_notify_helper));
- break;
- case RT_DEVICE_CTRL_CLR_INT:
- /* Disable RX */
- port_dev->rx_notify = RT_FALSE;
- break;
- case RT_DEVICE_CTRL_SET_INT:
- /* Enable RX */
- port_dev->rx_notify = RT_TRUE;
- break;
- case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY:
- {
- port_dev->need_destroy = RT_TRUE;
- port_dev->rx_notify = RT_FALSE;
- }
- break;
- default:
- status = -RT_EINVAL;
- break;
- }
- return status;
- }
- static rt_err_t virtio_console_init(rt_device_t dev)
- {
- struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
- if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- rt_uint16_t id;
- rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
- struct virtq *queue_ctrl_rx, *queue_ctrl_tx;
- queue_ctrl_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
- queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
- virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, queue_ctrl_rx->num, idx);
- virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, queue_ctrl_tx->num, idx);
- for (id = 0; id < queue_ctrl_rx->num; ++id)
- {
- void *addr = &virtio_console_dev->info[id].rx_ctrl;
- virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, id,
- VIRTIO_VA2PA(addr), sizeof(struct virtio_console_control), VIRTQ_DESC_F_WRITE, 0);
- queue_ctrl_rx->avail->ring[id] = id;
- }
- rt_hw_dsb();
- for (id = 0; id < queue_ctrl_tx->num; ++id)
- {
- virtio_console_dev->info[id].tx_ctrl_paddr = VIRTIO_VA2PA(&virtio_console_dev->info[id].tx_ctrl);
- }
- queue_ctrl_rx->avail->flags = 0;
- queue_ctrl_rx->avail->idx = queue_ctrl_rx->num;
- queue_ctrl_rx->used_idx = queue_ctrl_rx->used->idx;
- queue_ctrl_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
- queue_ctrl_tx->avail->idx = 0;
- virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX);
- }
- return virtio_console_port_create(virtio_console_dev);
- }
- static rt_err_t virtio_console_control(rt_device_t dev, int cmd, void *args)
- {
- rt_err_t status = RT_EOK;
- struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
- switch (cmd)
- {
- case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE:
- status = virtio_console_port_create(virtio_console_dev);
- break;
- default:
- status = -RT_EINVAL;
- break;
- }
- return status;
- }
- #ifdef RT_USING_DEVICE_OPS
- const static struct rt_device_ops virtio_console_ops =
- {
- virtio_console_init,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- virtio_console_control
- };
- #endif
- static void virtio_console_isr(int irqno, void *param)
- {
- rt_uint32_t id;
- rt_uint32_t len;
- struct port_device *port_dev;
- struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)param;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
- const char *dev_name = virtio_console_dev->parent.parent.name;
- #ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
- #endif
- virtio_interrupt_ack(virtio_dev);
- rt_hw_dsb();
- do {
- struct virtq *queue_rx;
- struct virtio_console_control *ctrl, set_ctrl;
- if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- break;
- }
- queue_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
- if (queue_rx->used_idx == queue_rx->used->idx)
- {
- break;
- }
- rt_hw_dsb();
- id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
- len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
- queue_rx->used_idx++;
- if (len != sizeof(struct virtio_console_control))
- {
- rt_kprintf("%s: Invalid ctrl!\n", dev_name);
- break;
- }
- ctrl = &virtio_console_dev->info[id].rx_ctrl;
- switch (ctrl->event)
- {
- case VIRTIO_CONSOLE_PORT_ADD:
- {
- set_ctrl.id = ctrl->id;
- set_ctrl.event = VIRTIO_CONSOLE_PORT_READY;
- set_ctrl.value = 1;
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
- #endif
- virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
- #ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
- #endif
- }
- break;
- case VIRTIO_CONSOLE_PORT_REMOVE:
- break;
- case VIRTIO_CONSOLE_RESIZE:
- break;
- case VIRTIO_CONSOLE_PORT_OPEN:
- {
- set_ctrl.id = ctrl->id;
- set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
- set_ctrl.value = 1;
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
- #endif
- virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
- #ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
- #endif
- }
- break;
- case VIRTIO_CONSOLE_PORT_NAME:
- break;
- default:
- rt_kprintf("%s: Unsupport ctrl[id: %d, event: %d, value: %d]!\n",
- dev_name, ctrl->id, ctrl->event, ctrl->value);
- break;
- }
- } while (0);
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
- #endif
- rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
- {
- rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
- struct virtq *queue_rx = port_dev->queue_rx;
- #ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
- #endif
- if (queue_rx->used_idx != queue_rx->used->idx)
- {
- rt_hw_dsb();
- id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
- len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
- if (port_dev->rx_notify)
- {
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
- #endif
- /* Will call virtio_console_port_read to inc used_idx */
- if (port_dev->parent.rx_indicate != RT_NULL)
- {
- port_dev->parent.rx_indicate(&port_dev->parent, len);
- }
- if (port_dev->rx_notify_helper.notify != RT_NULL)
- {
- port_dev->rx_notify_helper.notify(port_dev->rx_notify_helper.dev);
- }
- #ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
- #endif
- }
- else
- {
- queue_rx->used_idx++;
- virtio_submit_chain(virtio_dev, queue_rx_index, id);
- virtio_queue_notify(virtio_dev, queue_rx_index);
- }
- }
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
- #endif
- }
- }
- rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
- {
- int i;
- rt_size_t queues_num;
- static int dev_no = 0;
- char dev_name[RT_NAME_MAX];
- struct virtio_device *virtio_dev;
- struct virtio_console_device *virtio_console_dev;
- RT_ASSERT(RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR > 0);
- virtio_console_dev = rt_malloc(sizeof(struct virtio_console_device));
- if (virtio_console_dev == RT_NULL)
- {
- goto _alloc_fail;
- }
- virtio_dev = &virtio_console_dev->virtio_dev;
- virtio_dev->irq = irq;
- virtio_dev->mmio_base = mmio_base;
- virtio_console_dev->config = (struct virtio_console_config *)virtio_dev->mmio_config->config;
- #ifdef RT_USING_SMP
- rt_spin_lock_init(&virtio_dev->spinlock);
- #endif
- virtio_reset_device(virtio_dev);
- virtio_status_acknowledge_driver(virtio_dev);
- virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
- (1 << VIRTIO_F_RING_EVENT_IDX) |
- (1 << VIRTIO_F_RING_INDIRECT_DESC));
- virtio_status_driver_ok(virtio_dev);
- if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- virtio_console_dev->max_port_nr = 1;
- queues_num = 2;
- }
- else
- {
- if (virtio_console_dev->config->max_nr_ports > RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR)
- {
- virtio_console_dev->max_port_nr = RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR;
- virtio_console_dev->config->max_nr_ports = virtio_console_dev->max_port_nr;
- }
- else
- {
- virtio_console_dev->max_port_nr = virtio_console_dev->config->max_nr_ports;
- }
- queues_num = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(virtio_console_dev->max_port_nr, VIRTIO_CONSOLE_QUEUE_DATA_RX);
- }
- if (virtio_queues_alloc(virtio_dev, queues_num) != RT_EOK)
- {
- goto _alloc_fail;
- }
- for (i = 0; i < virtio_dev->queues_num; ++i)
- {
- if (virtio_queue_init(virtio_dev, i, VIRTIO_CONSOLE_QUEUE_SIZE) != RT_EOK)
- {
- for (; i >= 0; --i)
- {
- virtio_queue_destroy(virtio_dev, i);
- }
- goto _alloc_fail;
- }
- }
- virtio_console_dev->parent.type = RT_Device_Class_Char;
- #ifdef RT_USING_DEVICE_OPS
- virtio_console_dev->parent.ops = &virtio_console_ops;
- #else
- virtio_console_dev->parent.init = virtio_console_init;
- virtio_console_dev->parent.open = RT_NULL;
- virtio_console_dev->parent.close = RT_NULL;
- virtio_console_dev->parent.read = RT_NULL;
- virtio_console_dev->parent.write = RT_NULL;
- virtio_console_dev->parent.control = virtio_console_control;
- #endif
- virtio_console_dev->parent.rx_indicate = RT_NULL;
- virtio_console_dev->parent.tx_complete = RT_NULL;
- virtio_console_dev->console_id = dev_no;
- virtio_console_dev->port_nr = 0;
- rt_list_init(&virtio_console_dev->port_head);
- rt_snprintf(dev_name, RT_NAME_MAX, "virtio-console%d", dev_no++);
- rt_hw_interrupt_install(irq, virtio_console_isr, virtio_console_dev, dev_name);
- rt_hw_interrupt_umask(irq);
- return rt_device_register((rt_device_t)virtio_console_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
- _alloc_fail:
- if (virtio_console_dev != RT_NULL)
- {
- virtio_queues_free(virtio_dev);
- rt_free(virtio_console_dev);
- }
- return -RT_ENOMEM;
- }
- #endif /* RT_USING_VIRTIO_CONSOLE */
|