xref: /openbmc/qemu/chardev/testdev.c (revision f4ef8c9cc10b3bee829b9775879d4ff9f77c2442)
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