]> git.proxmox.com Git - mirror_qemu.git/blob - backends/testdev.c
char: rename CharDriverState Chardev
[mirror_qemu.git] / backends / testdev.c
1 /*
2 * QEMU Char Device for testsuite control
3 *
4 * Copyright (c) 2014 Red Hat, Inc.
5 *
6 * Author: Paolo Bonzini <pbonzini@redhat.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26 #include "qemu/osdep.h"
27 #include "qemu-common.h"
28 #include "sysemu/char.h"
29
30 #define BUF_SIZE 32
31
32 typedef struct {
33 Chardev parent;
34
35 uint8_t in_buf[32];
36 int in_buf_used;
37 } TestdevChardev;
38
39 /* Try to interpret a whole incoming packet */
40 static int testdev_eat_packet(TestdevChardev *testdev)
41 {
42 const uint8_t *cur = testdev->in_buf;
43 int len = testdev->in_buf_used;
44 uint8_t c;
45 int arg;
46
47 #define EAT(c) do { \
48 if (!len--) { \
49 return 0; \
50 } \
51 c = *cur++; \
52 } while (0)
53
54 EAT(c);
55
56 while (isspace(c)) {
57 EAT(c);
58 }
59
60 arg = 0;
61 while (isdigit(c)) {
62 arg = arg * 10 + c - '0';
63 EAT(c);
64 }
65
66 while (isspace(c)) {
67 EAT(c);
68 }
69
70 switch (c) {
71 case 'q':
72 exit((arg << 1) | 1);
73 break;
74 default:
75 break;
76 }
77 return cur - testdev->in_buf;
78 }
79
80 /* The other end is writing some data. Store it and try to interpret */
81 static int testdev_write(Chardev *chr, const uint8_t *buf, int len)
82 {
83 TestdevChardev *testdev = (TestdevChardev *)chr;
84 int tocopy, eaten, orig_len = len;
85
86 while (len) {
87 /* Complete our buffer as much as possible */
88 tocopy = MIN(len, BUF_SIZE - testdev->in_buf_used);
89
90 memcpy(testdev->in_buf + testdev->in_buf_used, buf, tocopy);
91 testdev->in_buf_used += tocopy;
92 buf += tocopy;
93 len -= tocopy;
94
95 /* Interpret it as much as possible */
96 while (testdev->in_buf_used > 0 &&
97 (eaten = testdev_eat_packet(testdev)) > 0) {
98 memmove(testdev->in_buf, testdev->in_buf + eaten,
99 testdev->in_buf_used - eaten);
100 testdev->in_buf_used -= eaten;
101 }
102 }
103 return orig_len;
104 }
105
106 static Chardev *chr_testdev_init(const CharDriver *driver,
107 const char *id,
108 ChardevBackend *backend,
109 ChardevReturn *ret,
110 bool *be_opened,
111 Error **errp)
112 {
113 TestdevChardev *testdev = g_new0(TestdevChardev, 1);;
114 Chardev *chr = (Chardev *)testdev;
115
116 chr->driver = driver;
117
118 return chr;
119 }
120
121 static void register_types(void)
122 {
123 static const CharDriver driver = {
124 .instance_size = sizeof(TestdevChardev),
125 .kind = CHARDEV_BACKEND_KIND_TESTDEV,
126 .create = chr_testdev_init,
127 .chr_write = testdev_write,
128 };
129 register_char_driver(&driver);
130 }
131
132 type_init(register_types);