Statistics
| Branch: | Revision:

root / hw / virtio-console.c @ 513f789f

History | View | Annotate | Download (4 kB)

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