Add qemu 2.4.0
[kvmfornfv.git] / qemu / 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-common.h"
27 #include "sysemu/char.h"
28
29 #define BUF_SIZE 32
30
31 typedef struct {
32     CharDriverState *chr;
33     uint8_t in_buf[32];
34     int in_buf_used;
35 } TestdevCharState;
36
37 /* Try to interpret a whole incoming packet */
38 static int testdev_eat_packet(TestdevCharState *testdev)
39 {
40     const uint8_t *cur = testdev->in_buf;
41     int len = testdev->in_buf_used;
42     uint8_t c;
43     int arg;
44
45 #define EAT(c) do { \
46     if (!len--) {   \
47         return 0;   \
48     }               \
49     c = *cur++;     \
50 } while (0)
51
52     EAT(c);
53
54     while (isspace(c)) {
55         EAT(c);
56     }
57
58     arg = 0;
59     while (isdigit(c)) {
60         arg = arg * 10 + c - '0';
61         EAT(c);
62     }
63
64     while (isspace(c)) {
65         EAT(c);
66     }
67
68     switch (c) {
69     case 'q':
70         exit((arg << 1) | 1);
71         break;
72     default:
73         break;
74     }
75     return cur - testdev->in_buf;
76 }
77
78 /* The other end is writing some data.  Store it and try to interpret */
79 static int testdev_write(CharDriverState *chr, const uint8_t *buf, int len)
80 {
81     TestdevCharState *testdev = chr->opaque;
82     int tocopy, eaten, orig_len = len;
83
84     while (len) {
85         /* Complete our buffer as much as possible */
86         tocopy = MIN(len, BUF_SIZE - testdev->in_buf_used);
87
88         memcpy(testdev->in_buf + testdev->in_buf_used, buf, tocopy);
89         testdev->in_buf_used += tocopy;
90         buf += tocopy;
91         len -= tocopy;
92
93         /* Interpret it as much as possible */
94         while (testdev->in_buf_used > 0 &&
95                (eaten = testdev_eat_packet(testdev)) > 0) {
96             memmove(testdev->in_buf, testdev->in_buf + eaten,
97                     testdev->in_buf_used - eaten);
98             testdev->in_buf_used -= eaten;
99         }
100     }
101     return orig_len;
102 }
103
104 static void testdev_close(struct CharDriverState *chr)
105 {
106     TestdevCharState *testdev = chr->opaque;
107
108     g_free(testdev);
109 }
110
111 CharDriverState *chr_testdev_init(void)
112 {
113     TestdevCharState *testdev;
114     CharDriverState *chr;
115
116     testdev = g_malloc0(sizeof(TestdevCharState));
117     testdev->chr = chr = g_malloc0(sizeof(CharDriverState));
118
119     chr->opaque = testdev;
120     chr->chr_write = testdev_write;
121     chr->chr_close = testdev_close;
122
123     return chr;
124 }
125
126 static void register_types(void)
127 {
128     register_char_driver("testdev", CHARDEV_BACKEND_KIND_TESTDEV, NULL);
129 }
130
131 type_init(register_types);