16b10e573SMarc-André Lureau /*
26b10e573SMarc-André Lureau * QEMU Char Device for testsuite control
36b10e573SMarc-André Lureau *
46b10e573SMarc-André Lureau * Copyright (c) 2014 Red Hat, Inc.
56b10e573SMarc-André Lureau *
66b10e573SMarc-André Lureau * Author: Paolo Bonzini <pbonzini@redhat.com>
76b10e573SMarc-André Lureau *
86b10e573SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy
96b10e573SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal
106b10e573SMarc-André Lureau * in the Software without restriction, including without limitation the rights
116b10e573SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
126b10e573SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is
136b10e573SMarc-André Lureau * furnished to do so, subject to the following conditions:
146b10e573SMarc-André Lureau *
156b10e573SMarc-André Lureau * The above copyright notice and this permission notice shall be included in
166b10e573SMarc-André Lureau * all copies or substantial portions of the Software.
176b10e573SMarc-André Lureau *
186b10e573SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
196b10e573SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
206b10e573SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
216b10e573SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
226b10e573SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
236b10e573SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
246b10e573SMarc-André Lureau * THE SOFTWARE.
256b10e573SMarc-André Lureau */
260b8fa32fSMarkus Armbruster
276b10e573SMarc-André Lureau #include "qemu/osdep.h"
280b8fa32fSMarkus Armbruster #include "qemu/module.h"
296b10e573SMarc-André Lureau #include "chardev/char.h"
30db1015e9SEduardo Habkost #include "qom/object.h"
316b10e573SMarc-André Lureau
326b10e573SMarc-André Lureau #define BUF_SIZE 32
336b10e573SMarc-André Lureau
34db1015e9SEduardo Habkost struct TestdevChardev {
356b10e573SMarc-André Lureau Chardev parent;
366b10e573SMarc-André Lureau
376b10e573SMarc-André Lureau uint8_t in_buf[32];
386b10e573SMarc-André Lureau int in_buf_used;
39db1015e9SEduardo Habkost };
40db1015e9SEduardo Habkost typedef struct TestdevChardev TestdevChardev;
416b10e573SMarc-André Lureau
426b10e573SMarc-André Lureau #define TYPE_CHARDEV_TESTDEV "chardev-testdev"
DECLARE_INSTANCE_CHECKER(TestdevChardev,TESTDEV_CHARDEV,TYPE_CHARDEV_TESTDEV)43*8110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(TestdevChardev, TESTDEV_CHARDEV,
44*8110fa1dSEduardo Habkost TYPE_CHARDEV_TESTDEV)
456b10e573SMarc-André Lureau
466b10e573SMarc-André Lureau /* Try to interpret a whole incoming packet */
476b10e573SMarc-André Lureau static int testdev_eat_packet(TestdevChardev *testdev)
486b10e573SMarc-André Lureau {
496b10e573SMarc-André Lureau const uint8_t *cur = testdev->in_buf;
506b10e573SMarc-André Lureau int len = testdev->in_buf_used;
516b10e573SMarc-André Lureau uint8_t c;
526b10e573SMarc-André Lureau int arg;
536b10e573SMarc-André Lureau
546b10e573SMarc-André Lureau #define EAT(c) do { \
556b10e573SMarc-André Lureau if (!len--) { \
566b10e573SMarc-André Lureau return 0; \
576b10e573SMarc-André Lureau } \
586b10e573SMarc-André Lureau c = *cur++; \
596b10e573SMarc-André Lureau } while (0)
606b10e573SMarc-André Lureau
616b10e573SMarc-André Lureau EAT(c);
626b10e573SMarc-André Lureau
636b10e573SMarc-André Lureau while (isspace(c)) {
646b10e573SMarc-André Lureau EAT(c);
656b10e573SMarc-André Lureau }
666b10e573SMarc-André Lureau
676b10e573SMarc-André Lureau arg = 0;
686b10e573SMarc-André Lureau while (isdigit(c)) {
696b10e573SMarc-André Lureau arg = arg * 10 + c - '0';
706b10e573SMarc-André Lureau EAT(c);
716b10e573SMarc-André Lureau }
726b10e573SMarc-André Lureau
736b10e573SMarc-André Lureau while (isspace(c)) {
746b10e573SMarc-André Lureau EAT(c);
756b10e573SMarc-André Lureau }
766b10e573SMarc-André Lureau
776b10e573SMarc-André Lureau switch (c) {
786b10e573SMarc-André Lureau case 'q':
796b10e573SMarc-André Lureau exit((arg << 1) | 1);
806b10e573SMarc-André Lureau break;
816b10e573SMarc-André Lureau default:
826b10e573SMarc-André Lureau break;
836b10e573SMarc-André Lureau }
846b10e573SMarc-André Lureau return cur - testdev->in_buf;
856b10e573SMarc-André Lureau }
866b10e573SMarc-André Lureau
876b10e573SMarc-André Lureau /* The other end is writing some data. Store it and try to interpret */
testdev_chr_write(Chardev * chr,const uint8_t * buf,int len)886b10e573SMarc-André Lureau static int testdev_chr_write(Chardev *chr, const uint8_t *buf, int len)
896b10e573SMarc-André Lureau {
906b10e573SMarc-André Lureau TestdevChardev *testdev = TESTDEV_CHARDEV(chr);
916b10e573SMarc-André Lureau int tocopy, eaten, orig_len = len;
926b10e573SMarc-André Lureau
936b10e573SMarc-André Lureau while (len) {
946b10e573SMarc-André Lureau /* Complete our buffer as much as possible */
956b10e573SMarc-André Lureau tocopy = MIN(len, BUF_SIZE - testdev->in_buf_used);
966b10e573SMarc-André Lureau
976b10e573SMarc-André Lureau memcpy(testdev->in_buf + testdev->in_buf_used, buf, tocopy);
986b10e573SMarc-André Lureau testdev->in_buf_used += tocopy;
996b10e573SMarc-André Lureau buf += tocopy;
1006b10e573SMarc-André Lureau len -= tocopy;
1016b10e573SMarc-André Lureau
1026b10e573SMarc-André Lureau /* Interpret it as much as possible */
1036b10e573SMarc-André Lureau while (testdev->in_buf_used > 0 &&
1046b10e573SMarc-André Lureau (eaten = testdev_eat_packet(testdev)) > 0) {
1056b10e573SMarc-André Lureau memmove(testdev->in_buf, testdev->in_buf + eaten,
1066b10e573SMarc-André Lureau testdev->in_buf_used - eaten);
1076b10e573SMarc-André Lureau testdev->in_buf_used -= eaten;
1086b10e573SMarc-André Lureau }
1096b10e573SMarc-André Lureau }
1106b10e573SMarc-André Lureau return orig_len;
1116b10e573SMarc-André Lureau }
1126b10e573SMarc-André Lureau
char_testdev_class_init(ObjectClass * oc,void * data)1136b10e573SMarc-André Lureau static void char_testdev_class_init(ObjectClass *oc, void *data)
1146b10e573SMarc-André Lureau {
1156b10e573SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc);
1166b10e573SMarc-André Lureau
1176b10e573SMarc-André Lureau cc->chr_write = testdev_chr_write;
1186b10e573SMarc-André Lureau }
1196b10e573SMarc-André Lureau
1206b10e573SMarc-André Lureau static const TypeInfo char_testdev_type_info = {
1216b10e573SMarc-André Lureau .name = TYPE_CHARDEV_TESTDEV,
1226b10e573SMarc-André Lureau .parent = TYPE_CHARDEV,
1236b10e573SMarc-André Lureau .instance_size = sizeof(TestdevChardev),
1246b10e573SMarc-André Lureau .class_init = char_testdev_class_init,
1256b10e573SMarc-André Lureau };
1266b10e573SMarc-André Lureau
register_types(void)1276b10e573SMarc-André Lureau static void register_types(void)
1286b10e573SMarc-André Lureau {
1296b10e573SMarc-André Lureau type_register_static(&char_testdev_type_info);
1306b10e573SMarc-André Lureau }
1316b10e573SMarc-André Lureau
1326b10e573SMarc-André Lureau type_init(register_types);
133