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