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