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