Annotation of qemu/hw/virtio-console.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Virtio Console Device
        !             3:  *
        !             4:  * Copyright IBM, Corp. 2008
        !             5:  *
        !             6:  * Authors:
        !             7:  *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
        !             8:  *
        !             9:  * This work is licensed under the terms of the GNU GPL, version 2.  See
        !            10:  * the COPYING file in the top-level directory.
        !            11:  *
        !            12:  */
        !            13: 
        !            14: #include "hw.h"
        !            15: #include "qemu-char.h"
        !            16: #include "virtio.h"
        !            17: #include "virtio-console.h"
        !            18: 
        !            19: 
        !            20: typedef struct VirtIOConsole
        !            21: {
        !            22:     VirtIODevice vdev;
        !            23:     VirtQueue *ivq, *dvq;
        !            24:     CharDriverState *chr;
        !            25: } VirtIOConsole;
        !            26: 
        !            27: static VirtIOConsole *to_virtio_console(VirtIODevice *vdev)
        !            28: {
        !            29:     return (VirtIOConsole *)vdev;
        !            30: }
        !            31: 
        !            32: static void virtio_console_handle_output(VirtIODevice *vdev, VirtQueue *vq)
        !            33: {
        !            34:     VirtIOConsole *s = to_virtio_console(vdev);
        !            35:     VirtQueueElement elem;
        !            36: 
        !            37:     while (virtqueue_pop(vq, &elem)) {
        !            38:         ssize_t len = 0;
        !            39:         int d;
        !            40: 
        !            41:         for (d=0; d < elem.out_num; d++)
        !            42:             len += qemu_chr_write(s->chr, elem.out_sg[d].iov_base,elem.out_sg[d].iov_len);
        !            43:         virtqueue_push(vq, &elem, len);
        !            44:         virtio_notify(vdev, vq);
        !            45:     }
        !            46: }
        !            47: 
        !            48: static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq)
        !            49: {
        !            50: }
        !            51: 
        !            52: static uint32_t virtio_console_get_features(VirtIODevice *vdev)
        !            53: {
        !            54:     return 0;
        !            55: }
        !            56: 
        !            57: static int vcon_can_read(void *opaque)
        !            58: {
        !            59:     VirtIOConsole *s = (VirtIOConsole *) opaque;
        !            60: 
        !            61:     if (!virtio_queue_ready(s->ivq) ||
        !            62:         !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
        !            63:         virtio_queue_empty(s->ivq))
        !            64:         return 0;
        !            65: 
        !            66:     /* current implementations have a page sized buffer.
        !            67:      * We fall back to a one byte per read if there is not enough room.
        !            68:      * It would be cool to have a function that returns the available byte
        !            69:      * instead of checking for a limit */
        !            70:     if (virtqueue_avail_bytes(s->ivq, TARGET_PAGE_SIZE, 0))
        !            71:         return TARGET_PAGE_SIZE;
        !            72:     if (virtqueue_avail_bytes(s->ivq, 1, 0))
        !            73:         return 1;
        !            74:     return 0;
        !            75: }
        !            76: 
        !            77: static void vcon_read(void *opaque, const uint8_t *buf, int size)
        !            78: {
        !            79:     VirtIOConsole *s = (VirtIOConsole *) opaque;
        !            80:     VirtQueueElement elem;
        !            81:     int offset = 0;
        !            82: 
        !            83:     /* The current kernel implementation has only one outstanding input
        !            84:      * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
        !            85:      * handle multiple buffers with multiple sg element for input */
        !            86:     while (offset < size) {
        !            87:         int i = 0;
        !            88:         if (!virtqueue_pop(s->ivq, &elem))
        !            89:                 break;
        !            90:         while (offset < size && i < elem.in_num) {
        !            91:             int len = MIN(elem.in_sg[i].iov_len, size - offset);
        !            92:             memcpy(elem.in_sg[i].iov_base, buf + offset, len);
        !            93:             offset += len;
        !            94:             i++;
        !            95:         }
        !            96:         virtqueue_push(s->ivq, &elem, size);
        !            97:     }
        !            98:     virtio_notify(&s->vdev, s->ivq);
        !            99: }
        !           100: 
        !           101: static void vcon_event(void *opaque, int event)
        !           102: {
        !           103:     /* we will ignore any event for the time being */
        !           104: }
        !           105: 
        !           106: static void virtio_console_save(QEMUFile *f, void *opaque)
        !           107: {
        !           108:     VirtIOConsole *s = opaque;
        !           109: 
        !           110:     virtio_save(&s->vdev, f);
        !           111: }
        !           112: 
        !           113: static int virtio_console_load(QEMUFile *f, void *opaque, int version_id)
        !           114: {
        !           115:     VirtIOConsole *s = opaque;
        !           116: 
        !           117:     if (version_id != 1)
        !           118:         return -EINVAL;
        !           119: 
        !           120:     virtio_load(&s->vdev, f);
        !           121:     return 0;
        !           122: }
        !           123: 
        !           124: void *virtio_console_init(PCIBus *bus, CharDriverState *chr)
        !           125: {
        !           126:     VirtIOConsole *s;
        !           127: 
        !           128:     s = (VirtIOConsole *)virtio_init_pci(bus, "virtio-console",
        !           129:                                          PCI_VENDOR_ID_REDHAT_QUMRANET,
        !           130:                                          PCI_DEVICE_ID_VIRTIO_CONSOLE,
        !           131:                                          PCI_VENDOR_ID_REDHAT_QUMRANET,
        !           132:                                          VIRTIO_ID_CONSOLE,
        !           133:                                          PCI_CLASS_DISPLAY_OTHER, 0x00,
        !           134:                                          0, sizeof(VirtIOConsole));
        !           135:     if (s == NULL)
        !           136:         return NULL;
        !           137: 
        !           138:     s->vdev.get_features = virtio_console_get_features;
        !           139: 
        !           140:     s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
        !           141:     s->dvq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
        !           142: 
        !           143:     s->chr = chr;
        !           144:     qemu_chr_add_handlers(chr, vcon_can_read, vcon_read, vcon_event, s);
        !           145: 
        !           146:     register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s);
        !           147: 
        !           148:     return &s->vdev;
        !           149: }

unix.superglobalmegacorp.com