xref: /qemu/chardev/testdev.c (revision a8260d38)
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 "chardev/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 #define TYPE_CHARDEV_TESTDEV "chardev-testdev"
40 #define TESTDEV_CHARDEV(obj)                                    \
41     OBJECT_CHECK(TestdevChardev, (obj), TYPE_CHARDEV_TESTDEV)
42 
43 /* Try to interpret a whole incoming packet */
44 static int testdev_eat_packet(TestdevChardev *testdev)
45 {
46     const uint8_t *cur = testdev->in_buf;
47     int len = testdev->in_buf_used;
48     uint8_t c;
49     int arg;
50 
51 #define EAT(c) do { \
52     if (!len--) {   \
53         return 0;   \
54     }               \
55     c = *cur++;     \
56 } while (0)
57 
58     EAT(c);
59 
60     while (isspace(c)) {
61         EAT(c);
62     }
63 
64     arg = 0;
65     while (isdigit(c)) {
66         arg = arg * 10 + c - '0';
67         EAT(c);
68     }
69 
70     while (isspace(c)) {
71         EAT(c);
72     }
73 
74     switch (c) {
75     case 'q':
76         exit((arg << 1) | 1);
77         break;
78     default:
79         break;
80     }
81     return cur - testdev->in_buf;
82 }
83 
84 /* The other end is writing some data.  Store it and try to interpret */
85 static int testdev_chr_write(Chardev *chr, const uint8_t *buf, int len)
86 {
87     TestdevChardev *testdev = TESTDEV_CHARDEV(chr);
88     int tocopy, eaten, orig_len = len;
89 
90     while (len) {
91         /* Complete our buffer as much as possible */
92         tocopy = MIN(len, BUF_SIZE - testdev->in_buf_used);
93 
94         memcpy(testdev->in_buf + testdev->in_buf_used, buf, tocopy);
95         testdev->in_buf_used += tocopy;
96         buf += tocopy;
97         len -= tocopy;
98 
99         /* Interpret it as much as possible */
100         while (testdev->in_buf_used > 0 &&
101                (eaten = testdev_eat_packet(testdev)) > 0) {
102             memmove(testdev->in_buf, testdev->in_buf + eaten,
103                     testdev->in_buf_used - eaten);
104             testdev->in_buf_used -= eaten;
105         }
106     }
107     return orig_len;
108 }
109 
110 static void char_testdev_class_init(ObjectClass *oc, void *data)
111 {
112     ChardevClass *cc = CHARDEV_CLASS(oc);
113 
114     cc->chr_write = testdev_chr_write;
115 }
116 
117 static const TypeInfo char_testdev_type_info = {
118     .name = TYPE_CHARDEV_TESTDEV,
119     .parent = TYPE_CHARDEV,
120     .instance_size = sizeof(TestdevChardev),
121     .class_init = char_testdev_class_init,
122 };
123 
124 static void register_types(void)
125 {
126     type_register_static(&char_testdev_type_info);
127 }
128 
129 type_init(register_types);
130