root / hw / virtio-console.c @ f7b4f61f
History | View | Annotate | Download (3.8 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 | bf0cb498 | Amit Shah | VirtQueue *ivq, *ovq; |
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 | 3f4cb3d3 | blueswir1 | for (d = 0; d < elem.out_num; d++) { |
42 | 3f4cb3d3 | blueswir1 | len += qemu_chr_write(s->chr, (uint8_t *)elem.out_sg[d].iov_base, |
43 | 3f4cb3d3 | blueswir1 | elem.out_sg[d].iov_len); |
44 | 3f4cb3d3 | blueswir1 | } |
45 | 970d878c | aliguori | virtqueue_push(vq, &elem, len); |
46 | 970d878c | aliguori | virtio_notify(vdev, vq); |
47 | 970d878c | aliguori | } |
48 | 970d878c | aliguori | } |
49 | 970d878c | aliguori | |
50 | 970d878c | aliguori | static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq) |
51 | 970d878c | aliguori | { |
52 | 970d878c | aliguori | } |
53 | 970d878c | aliguori | |
54 | 970d878c | aliguori | static uint32_t virtio_console_get_features(VirtIODevice *vdev)
|
55 | 970d878c | aliguori | { |
56 | 970d878c | aliguori | return 0; |
57 | 970d878c | aliguori | } |
58 | 970d878c | aliguori | |
59 | 970d878c | aliguori | static int vcon_can_read(void *opaque) |
60 | 970d878c | aliguori | { |
61 | 970d878c | aliguori | VirtIOConsole *s = (VirtIOConsole *) opaque; |
62 | 970d878c | aliguori | |
63 | 970d878c | aliguori | if (!virtio_queue_ready(s->ivq) ||
|
64 | 970d878c | aliguori | !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) || |
65 | 970d878c | aliguori | virtio_queue_empty(s->ivq)) |
66 | 970d878c | aliguori | return 0; |
67 | 970d878c | aliguori | |
68 | 970d878c | aliguori | /* current implementations have a page sized buffer.
|
69 | 970d878c | aliguori | * We fall back to a one byte per read if there is not enough room.
|
70 | 970d878c | aliguori | * It would be cool to have a function that returns the available byte
|
71 | 970d878c | aliguori | * instead of checking for a limit */
|
72 | 970d878c | aliguori | if (virtqueue_avail_bytes(s->ivq, TARGET_PAGE_SIZE, 0)) |
73 | 970d878c | aliguori | return TARGET_PAGE_SIZE;
|
74 | 970d878c | aliguori | if (virtqueue_avail_bytes(s->ivq, 1, 0)) |
75 | 970d878c | aliguori | return 1; |
76 | 970d878c | aliguori | return 0; |
77 | 970d878c | aliguori | } |
78 | 970d878c | aliguori | |
79 | 970d878c | aliguori | static void vcon_read(void *opaque, const uint8_t *buf, int size) |
80 | 970d878c | aliguori | { |
81 | 970d878c | aliguori | VirtIOConsole *s = (VirtIOConsole *) opaque; |
82 | 970d878c | aliguori | VirtQueueElement elem; |
83 | 970d878c | aliguori | int offset = 0; |
84 | 970d878c | aliguori | |
85 | 970d878c | aliguori | /* The current kernel implementation has only one outstanding input
|
86 | 970d878c | aliguori | * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
|
87 | 970d878c | aliguori | * handle multiple buffers with multiple sg element for input */
|
88 | 970d878c | aliguori | while (offset < size) {
|
89 | 970d878c | aliguori | int i = 0; |
90 | 970d878c | aliguori | if (!virtqueue_pop(s->ivq, &elem))
|
91 | 970d878c | aliguori | break;
|
92 | 970d878c | aliguori | while (offset < size && i < elem.in_num) {
|
93 | 970d878c | aliguori | int len = MIN(elem.in_sg[i].iov_len, size - offset);
|
94 | 970d878c | aliguori | memcpy(elem.in_sg[i].iov_base, buf + offset, len); |
95 | 970d878c | aliguori | offset += len; |
96 | 970d878c | aliguori | i++; |
97 | 970d878c | aliguori | } |
98 | 970d878c | aliguori | virtqueue_push(s->ivq, &elem, size); |
99 | 970d878c | aliguori | } |
100 | 970d878c | aliguori | virtio_notify(&s->vdev, s->ivq); |
101 | 970d878c | aliguori | } |
102 | 970d878c | aliguori | |
103 | 970d878c | aliguori | static void vcon_event(void *opaque, int event) |
104 | 970d878c | aliguori | { |
105 | 970d878c | aliguori | /* we will ignore any event for the time being */
|
106 | 970d878c | aliguori | } |
107 | 970d878c | aliguori | |
108 | 970d878c | aliguori | static void virtio_console_save(QEMUFile *f, void *opaque) |
109 | 970d878c | aliguori | { |
110 | 970d878c | aliguori | VirtIOConsole *s = opaque; |
111 | 970d878c | aliguori | |
112 | 970d878c | aliguori | virtio_save(&s->vdev, f); |
113 | 970d878c | aliguori | } |
114 | 970d878c | aliguori | |
115 | 970d878c | aliguori | static int virtio_console_load(QEMUFile *f, void *opaque, int version_id) |
116 | 970d878c | aliguori | { |
117 | 970d878c | aliguori | VirtIOConsole *s = opaque; |
118 | 970d878c | aliguori | |
119 | 970d878c | aliguori | if (version_id != 1) |
120 | 970d878c | aliguori | return -EINVAL;
|
121 | 970d878c | aliguori | |
122 | 970d878c | aliguori | virtio_load(&s->vdev, f); |
123 | 970d878c | aliguori | return 0; |
124 | 970d878c | aliguori | } |
125 | 970d878c | aliguori | |
126 | 53c25cea | Paul Brook | VirtIODevice *virtio_console_init(DeviceState *dev) |
127 | 970d878c | aliguori | { |
128 | 970d878c | aliguori | VirtIOConsole *s; |
129 | 53c25cea | Paul Brook | s = (VirtIOConsole *)virtio_common_init("virtio-console",
|
130 | 53c25cea | Paul Brook | VIRTIO_ID_CONSOLE, |
131 | 53c25cea | Paul Brook | 0, sizeof(VirtIOConsole)); |
132 | 970d878c | aliguori | s->vdev.get_features = virtio_console_get_features; |
133 | 970d878c | aliguori | |
134 | 970d878c | aliguori | s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
|
135 | bf0cb498 | Amit Shah | s->ovq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
|
136 | 970d878c | aliguori | |
137 | 53c25cea | Paul Brook | s->chr = qdev_init_chardev(dev); |
138 | 0e058a8a | Paul Brook | qemu_chr_add_handlers(s->chr, vcon_can_read, vcon_read, vcon_event, s); |
139 | 970d878c | aliguori | |
140 | 970d878c | aliguori | register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s); |
141 | 970d878c | aliguori | |
142 | 53c25cea | Paul Brook | return &s->vdev;
|
143 | 970d878c | aliguori | } |