xref: /openbmc/qemu/hw/char/sclpconsole-lm.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
16a444f85SHeinz Graalfs /*
26a444f85SHeinz Graalfs  * SCLP event types
36a444f85SHeinz Graalfs  *    Operations Command - Line Mode input
46a444f85SHeinz Graalfs  *    Message            - Line Mode output
56a444f85SHeinz Graalfs  *
66a444f85SHeinz Graalfs  * Copyright IBM, Corp. 2013
76a444f85SHeinz Graalfs  *
86a444f85SHeinz Graalfs  * Authors:
96a444f85SHeinz Graalfs  *  Heinz Graalfs <graalfs@linux.vnet.ibm.com>
106a444f85SHeinz Graalfs  *
116a444f85SHeinz Graalfs  * This work is licensed under the terms of the GNU GPL, version 2 or (at your
126a444f85SHeinz Graalfs  * option) any later version.  See the COPYING file in the top-level directory.
136a444f85SHeinz Graalfs  *
146a444f85SHeinz Graalfs  */
156a444f85SHeinz Graalfs 
169615495aSPeter Maydell #include "qemu/osdep.h"
176a444f85SHeinz Graalfs #include "qemu/thread.h"
186a444f85SHeinz Graalfs #include "qemu/error-report.h"
190b8fa32fSMarkus Armbruster #include "qemu/module.h"
204d43a603SMarc-André Lureau #include "chardev/char-fe.h"
216a444f85SHeinz Graalfs 
226a444f85SHeinz Graalfs #include "hw/s390x/sclp.h"
23d6454270SMarkus Armbruster #include "migration/vmstate.h"
246a444f85SHeinz Graalfs #include "hw/s390x/event-facility.h"
25a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
26ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
276a444f85SHeinz Graalfs #include "hw/s390x/ebcdic.h"
28db1015e9SEduardo Habkost #include "qom/object.h"
296a444f85SHeinz Graalfs 
306a444f85SHeinz Graalfs #define SIZE_BUFFER 4096
316a444f85SHeinz Graalfs #define NEWLINE     "\n"
326a444f85SHeinz Graalfs 
336a444f85SHeinz Graalfs typedef struct OprtnsCommand {
346a444f85SHeinz Graalfs     EventBufferHeader header;
356a444f85SHeinz Graalfs     MDMSU message_unit;
36880a7817SPhilippe Mathieu-Daudé     char data[];
376a444f85SHeinz Graalfs } QEMU_PACKED OprtnsCommand;
386a444f85SHeinz Graalfs 
396a444f85SHeinz Graalfs /* max size for line-mode data in 4K SCCB page */
406a444f85SHeinz Graalfs #define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand))
416a444f85SHeinz Graalfs 
42db1015e9SEduardo Habkost struct SCLPConsoleLM {
436a444f85SHeinz Graalfs     SCLPEvent event;
44becdfa00SMarc-André Lureau     CharBackend chr;
456a444f85SHeinz Graalfs     bool echo;                  /* immediate echo of input if true        */
466a444f85SHeinz Graalfs     uint32_t write_errors;      /* errors writing to char layer           */
476a444f85SHeinz Graalfs     uint32_t length;            /* length of byte stream in buffer        */
486a444f85SHeinz Graalfs     uint8_t buf[SIZE_CONSOLE_BUFFER];
49db1015e9SEduardo Habkost };
50db1015e9SEduardo Habkost typedef struct SCLPConsoleLM SCLPConsoleLM;
516a444f85SHeinz Graalfs 
52e563c59bSxiaoqiang zhao #define TYPE_SCLPLM_CONSOLE "sclplmconsole"
DECLARE_INSTANCE_CHECKER(SCLPConsoleLM,SCLPLM_CONSOLE,TYPE_SCLPLM_CONSOLE)538110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(SCLPConsoleLM, SCLPLM_CONSOLE,
548110fa1dSEduardo Habkost                          TYPE_SCLPLM_CONSOLE)
55e563c59bSxiaoqiang zhao 
566a444f85SHeinz Graalfs /*
576a444f85SHeinz Graalfs *  Character layer call-back functions
586a444f85SHeinz Graalfs  *
596a444f85SHeinz Graalfs  * Allow 1 character at a time
606a444f85SHeinz Graalfs  *
616a444f85SHeinz Graalfs  * Accumulate bytes from character layer in console buffer,
626a444f85SHeinz Graalfs  * event_pending is set when a newline character is encountered
636a444f85SHeinz Graalfs  *
646a444f85SHeinz Graalfs  * The maximum command line length is limited by the maximum
65b3191432SHeinz Graalfs  * space available in an SCCB. Line mode console input is sent
66b3191432SHeinz Graalfs  * truncated to the guest in case it doesn't fit into the SCCB.
676a444f85SHeinz Graalfs  */
686a444f85SHeinz Graalfs 
696a444f85SHeinz Graalfs static int chr_can_read(void *opaque)
706a444f85SHeinz Graalfs {
716a444f85SHeinz Graalfs     SCLPConsoleLM *scon = opaque;
726a444f85SHeinz Graalfs 
736a444f85SHeinz Graalfs     if (scon->event.event_pending) {
746a444f85SHeinz Graalfs         return 0;
756a444f85SHeinz Graalfs     }
76b3191432SHeinz Graalfs     return 1;
776a444f85SHeinz Graalfs }
786a444f85SHeinz Graalfs 
chr_read(void * opaque,const uint8_t * buf,int size)794f3ed190SChristian Borntraeger static void chr_read(void *opaque, const uint8_t *buf, int size)
806a444f85SHeinz Graalfs {
814f3ed190SChristian Borntraeger     SCLPConsoleLM *scon = opaque;
824f3ed190SChristian Borntraeger 
836a444f85SHeinz Graalfs     assert(size == 1);
846a444f85SHeinz Graalfs 
856a444f85SHeinz Graalfs     if (*buf == '\r' || *buf == '\n') {
866a444f85SHeinz Graalfs         scon->event.event_pending = true;
874f3ed190SChristian Borntraeger         sclp_service_interrupt(0);
886a444f85SHeinz Graalfs         return;
896a444f85SHeinz Graalfs     }
90b3191432SHeinz Graalfs     if (scon->length == SIZE_CONSOLE_BUFFER) {
91b3191432SHeinz Graalfs         /* Eat the character, but still process CR and LF.  */
92b3191432SHeinz Graalfs         return;
93b3191432SHeinz Graalfs     }
946a444f85SHeinz Graalfs     scon->buf[scon->length] = *buf;
956a444f85SHeinz Graalfs     scon->length += 1;
966a444f85SHeinz Graalfs     if (scon->echo) {
976ab3fc32SDaniel P. Berrange         /* XXX this blocks entire thread. Rewrite to use
986ab3fc32SDaniel P. Berrange          * qemu_chr_fe_write and background I/O callbacks */
995345fdb4SMarc-André Lureau         qemu_chr_fe_write_all(&scon->chr, buf, size);
1006a444f85SHeinz Graalfs     }
1016a444f85SHeinz Graalfs }
1026a444f85SHeinz Graalfs 
1036a444f85SHeinz Graalfs /* functions to be called by event facility */
1046a444f85SHeinz Graalfs 
can_handle_event(uint8_t type)1056a444f85SHeinz Graalfs static bool can_handle_event(uint8_t type)
1066a444f85SHeinz Graalfs {
1076a444f85SHeinz Graalfs     return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD;
1086a444f85SHeinz Graalfs }
1096a444f85SHeinz Graalfs 
send_mask(void)1101ffed98fSClaudio Imbrenda static sccb_mask_t send_mask(void)
1116a444f85SHeinz Graalfs {
1126a444f85SHeinz Graalfs     return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD;
1136a444f85SHeinz Graalfs }
1146a444f85SHeinz Graalfs 
receive_mask(void)1151ffed98fSClaudio Imbrenda static sccb_mask_t receive_mask(void)
1166a444f85SHeinz Graalfs {
1176a444f85SHeinz Graalfs     return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD;
1186a444f85SHeinz Graalfs }
1196a444f85SHeinz Graalfs 
1206a444f85SHeinz Graalfs /*
1216a444f85SHeinz Graalfs  * Triggered by SCLP's read_event_data
1226a444f85SHeinz Graalfs  * - convert ASCII byte stream to EBCDIC and
1236a444f85SHeinz Graalfs  * - copy converted data into provided (SCLP) buffer
1246a444f85SHeinz Graalfs  */
get_console_data(SCLPEvent * event,uint8_t * buf,size_t * size,int avail)1256a444f85SHeinz Graalfs static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
1266a444f85SHeinz Graalfs                             int avail)
1276a444f85SHeinz Graalfs {
1286a444f85SHeinz Graalfs     int len;
1296a444f85SHeinz Graalfs 
130e563c59bSxiaoqiang zhao     SCLPConsoleLM *cons = SCLPLM_CONSOLE(event);
1316a444f85SHeinz Graalfs 
1326a444f85SHeinz Graalfs     len = cons->length;
1336a444f85SHeinz Graalfs     /* data need to fit into provided SCLP buffer */
1346a444f85SHeinz Graalfs     if (len > avail) {
1356a444f85SHeinz Graalfs         return 1;
1366a444f85SHeinz Graalfs     }
1376a444f85SHeinz Graalfs 
1386a444f85SHeinz Graalfs     ebcdic_put(buf, (char *)&cons->buf, len);
1396a444f85SHeinz Graalfs     *size = len;
1406a444f85SHeinz Graalfs     cons->length = 0;
1416a444f85SHeinz Graalfs     /* data provided and no more data pending */
1426a444f85SHeinz Graalfs     event->event_pending = false;
14387f2eff0SHeinz Graalfs     qemu_notify_event();
1446a444f85SHeinz Graalfs     return 0;
1456a444f85SHeinz Graalfs }
1466a444f85SHeinz Graalfs 
read_event_data(SCLPEvent * event,EventBufferHeader * evt_buf_hdr,int * slen)1476a444f85SHeinz Graalfs static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
1486a444f85SHeinz Graalfs                            int *slen)
1496a444f85SHeinz Graalfs {
1506a444f85SHeinz Graalfs     int avail, rc;
1516a444f85SHeinz Graalfs     size_t src_len;
1526a444f85SHeinz Graalfs     uint8_t *to;
1536a444f85SHeinz Graalfs     OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr;
1546a444f85SHeinz Graalfs 
1556a444f85SHeinz Graalfs     if (!event->event_pending) {
1566a444f85SHeinz Graalfs         /* no data pending */
1576a444f85SHeinz Graalfs         return 0;
1586a444f85SHeinz Graalfs     }
1596a444f85SHeinz Graalfs 
1606a444f85SHeinz Graalfs     to = (uint8_t *)&oc->data;
1616a444f85SHeinz Graalfs     avail = *slen - sizeof(OprtnsCommand);
1626a444f85SHeinz Graalfs     rc = get_console_data(event, to, &src_len, avail);
1636a444f85SHeinz Graalfs     if (rc) {
1646a444f85SHeinz Graalfs         /* data didn't fit, try next SCCB */
1656a444f85SHeinz Graalfs         return 1;
1666a444f85SHeinz Graalfs     }
1676a444f85SHeinz Graalfs 
1686a444f85SHeinz Graalfs     oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU;
1696a444f85SHeinz Graalfs     oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU));
1706a444f85SHeinz Graalfs 
1716a444f85SHeinz Graalfs     oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU;
1726a444f85SHeinz Graalfs     oc->message_unit.cpmsu.length =
1736a444f85SHeinz Graalfs         cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector));
1746a444f85SHeinz Graalfs 
1756a444f85SHeinz Graalfs     oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD;
1766a444f85SHeinz Graalfs     oc->message_unit.text_command.length =
1776a444f85SHeinz Graalfs         cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector)));
1786a444f85SHeinz Graalfs 
1796a444f85SHeinz Graalfs     oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG;
1806a444f85SHeinz Graalfs     oc->message_unit.self_def_text_message.length =
1816a444f85SHeinz Graalfs         cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector)));
1826a444f85SHeinz Graalfs 
1836a444f85SHeinz Graalfs     oc->message_unit.text_message.key = GDS_KEY_TEXTMSG;
1846a444f85SHeinz Graalfs     oc->message_unit.text_message.length =
1856a444f85SHeinz Graalfs         cpu_to_be16(sizeof(GdsSubvector) + src_len);
1866a444f85SHeinz Graalfs 
1876a444f85SHeinz Graalfs     oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len);
1886a444f85SHeinz Graalfs     oc->header.type = SCLP_EVENT_OPRTNS_COMMAND;
1896a444f85SHeinz Graalfs     *slen = avail - src_len;
1906a444f85SHeinz Graalfs 
1916a444f85SHeinz Graalfs     return 1;
1926a444f85SHeinz Graalfs }
1936a444f85SHeinz Graalfs 
1946a444f85SHeinz Graalfs /*
1956a444f85SHeinz Graalfs  * Triggered by SCLP's write_event_data
1966a444f85SHeinz Graalfs  *  - write console data to character layer
1976a444f85SHeinz Graalfs  *  returns < 0 if an error occurred
1986a444f85SHeinz Graalfs  */
write_console_data(SCLPEvent * event,const uint8_t * buf,int len)1996a444f85SHeinz Graalfs static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
2006a444f85SHeinz Graalfs {
201e563c59bSxiaoqiang zhao     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
2026a444f85SHeinz Graalfs 
20330650701SAnton Nefedov     if (!qemu_chr_fe_backend_connected(&scon->chr)) {
2046a444f85SHeinz Graalfs         /* If there's no backend, we can just say we consumed all data. */
2056a444f85SHeinz Graalfs         return len;
2066a444f85SHeinz Graalfs     }
2076a444f85SHeinz Graalfs 
2087983e829SDaniel P. Berrange     /* XXX this blocks entire thread. Rewrite to use
2097983e829SDaniel P. Berrange      * qemu_chr_fe_write and background I/O callbacks */
2105345fdb4SMarc-André Lureau     return qemu_chr_fe_write_all(&scon->chr, buf, len);
2116a444f85SHeinz Graalfs }
2126a444f85SHeinz Graalfs 
process_mdb(SCLPEvent * event,MDBO * mdbo)2136a444f85SHeinz Graalfs static int process_mdb(SCLPEvent *event, MDBO *mdbo)
2146a444f85SHeinz Graalfs {
2156a444f85SHeinz Graalfs     int rc;
2166a444f85SHeinz Graalfs     int len;
2176a444f85SHeinz Graalfs     uint8_t buffer[SIZE_BUFFER];
2186a444f85SHeinz Graalfs 
2196a444f85SHeinz Graalfs     len = be16_to_cpu(mdbo->length);
2206a444f85SHeinz Graalfs     len -= sizeof(mdbo->length) + sizeof(mdbo->type)
2216a444f85SHeinz Graalfs             + sizeof(mdbo->mto.line_type_flags)
2226a444f85SHeinz Graalfs             + sizeof(mdbo->mto.alarm_control)
2236a444f85SHeinz Graalfs             + sizeof(mdbo->mto._reserved);
2246a444f85SHeinz Graalfs 
2256a444f85SHeinz Graalfs     assert(len <= SIZE_BUFFER);
2266a444f85SHeinz Graalfs 
2276a444f85SHeinz Graalfs     /* convert EBCDIC SCLP contents to ASCII console message */
2286a444f85SHeinz Graalfs     ascii_put(buffer, mdbo->mto.message, len);
2296a444f85SHeinz Graalfs     rc = write_console_data(event, (uint8_t *)NEWLINE, 1);
2306a444f85SHeinz Graalfs     if (rc < 0) {
2316a444f85SHeinz Graalfs         return rc;
2326a444f85SHeinz Graalfs     }
2336a444f85SHeinz Graalfs     return write_console_data(event, buffer, len);
2346a444f85SHeinz Graalfs }
2356a444f85SHeinz Graalfs 
write_event_data(SCLPEvent * event,EventBufferHeader * ebh)2366a444f85SHeinz Graalfs static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
2376a444f85SHeinz Graalfs {
2386a444f85SHeinz Graalfs     int len;
2396a444f85SHeinz Graalfs     int written;
2406a444f85SHeinz Graalfs     int errors = 0;
2416a444f85SHeinz Graalfs     MDBO *mdbo;
2426a444f85SHeinz Graalfs     SclpMsg *data = (SclpMsg *) ebh;
243e563c59bSxiaoqiang zhao     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
2446a444f85SHeinz Graalfs 
2456a444f85SHeinz Graalfs     len = be16_to_cpu(data->mdb.header.length);
2466a444f85SHeinz Graalfs     if (len < sizeof(data->mdb.header)) {
2476a444f85SHeinz Graalfs         return SCLP_RC_INCONSISTENT_LENGTHS;
2486a444f85SHeinz Graalfs     }
2496a444f85SHeinz Graalfs     len -= sizeof(data->mdb.header);
2506a444f85SHeinz Graalfs 
2516a444f85SHeinz Graalfs     /* first check message buffers */
2526a444f85SHeinz Graalfs     mdbo = data->mdb.mdbo;
2536a444f85SHeinz Graalfs     while (len > 0) {
2546a444f85SHeinz Graalfs         if (be16_to_cpu(mdbo->length) > len
2556a444f85SHeinz Graalfs                 || be16_to_cpu(mdbo->length) == 0) {
2566a444f85SHeinz Graalfs             return SCLP_RC_INCONSISTENT_LENGTHS;
2576a444f85SHeinz Graalfs         }
2586a444f85SHeinz Graalfs         len -= be16_to_cpu(mdbo->length);
2596a444f85SHeinz Graalfs         mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
2606a444f85SHeinz Graalfs     }
2616a444f85SHeinz Graalfs 
2626a444f85SHeinz Graalfs     /* then execute */
2636a444f85SHeinz Graalfs     len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header);
2646a444f85SHeinz Graalfs     mdbo = data->mdb.mdbo;
2656a444f85SHeinz Graalfs     while (len > 0) {
2666a444f85SHeinz Graalfs         switch (be16_to_cpu(mdbo->type)) {
2676a444f85SHeinz Graalfs         case MESSAGE_TEXT:
2686a444f85SHeinz Graalfs             /* message text object */
2696a444f85SHeinz Graalfs             written = process_mdb(event, mdbo);
2706a444f85SHeinz Graalfs             if (written < 0) {
2716a444f85SHeinz Graalfs                 /* character layer error */
2726a444f85SHeinz Graalfs                 errors++;
2736a444f85SHeinz Graalfs             }
2746a444f85SHeinz Graalfs             break;
2756a444f85SHeinz Graalfs         default: /* ignore */
2766a444f85SHeinz Graalfs             break;
2776a444f85SHeinz Graalfs         }
2786a444f85SHeinz Graalfs         len -= be16_to_cpu(mdbo->length);
2796a444f85SHeinz Graalfs         mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
2806a444f85SHeinz Graalfs     }
2816a444f85SHeinz Graalfs     if (errors) {
2826a444f85SHeinz Graalfs         scon->write_errors += errors;
2836a444f85SHeinz Graalfs     }
2846a444f85SHeinz Graalfs     data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED;
2856a444f85SHeinz Graalfs 
2866a444f85SHeinz Graalfs     return SCLP_RC_NORMAL_COMPLETION;
2876a444f85SHeinz Graalfs }
2886a444f85SHeinz Graalfs 
2896a444f85SHeinz Graalfs /* functions for live migration */
2906a444f85SHeinz Graalfs 
2916a444f85SHeinz Graalfs static const VMStateDescription vmstate_sclplmconsole = {
2926a444f85SHeinz Graalfs     .name = "sclplmconsole",
2936a444f85SHeinz Graalfs     .version_id = 0,
2946a444f85SHeinz Graalfs     .minimum_version_id = 0,
2952f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
2966a444f85SHeinz Graalfs         VMSTATE_BOOL(event.event_pending, SCLPConsoleLM),
2976a444f85SHeinz Graalfs         VMSTATE_UINT32(write_errors, SCLPConsoleLM),
2986a444f85SHeinz Graalfs         VMSTATE_UINT32(length, SCLPConsoleLM),
2996a444f85SHeinz Graalfs         VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER),
3006a444f85SHeinz Graalfs         VMSTATE_END_OF_LIST()
3016a444f85SHeinz Graalfs      }
3026a444f85SHeinz Graalfs };
3036a444f85SHeinz Graalfs 
3046a444f85SHeinz Graalfs /* qemu object creation and initialization functions */
3056a444f85SHeinz Graalfs 
3066a444f85SHeinz Graalfs /* tell character layer our call-back functions */
3076a444f85SHeinz Graalfs 
console_init(SCLPEvent * event)3086a444f85SHeinz Graalfs static int console_init(SCLPEvent *event)
3096a444f85SHeinz Graalfs {
3106a444f85SHeinz Graalfs     static bool console_available;
3116a444f85SHeinz Graalfs 
312e563c59bSxiaoqiang zhao     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
3136a444f85SHeinz Graalfs 
3146a444f85SHeinz Graalfs     if (console_available) {
3156a444f85SHeinz Graalfs         error_report("Multiple line-mode operator consoles are not supported");
3166a444f85SHeinz Graalfs         return -1;
3176a444f85SHeinz Graalfs     }
3186a444f85SHeinz Graalfs     console_available = true;
3196a444f85SHeinz Graalfs 
3205345fdb4SMarc-André Lureau     qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
32181517ba3SAnton Nefedov                              chr_read, NULL, NULL, scon, NULL, true);
3226a444f85SHeinz Graalfs 
3236a444f85SHeinz Graalfs     return 0;
3246a444f85SHeinz Graalfs }
3256a444f85SHeinz Graalfs 
console_reset(DeviceState * dev)3266a444f85SHeinz Graalfs static void console_reset(DeviceState *dev)
3276a444f85SHeinz Graalfs {
3286a444f85SHeinz Graalfs    SCLPEvent *event = SCLP_EVENT(dev);
329e563c59bSxiaoqiang zhao    SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
3306a444f85SHeinz Graalfs 
3316a444f85SHeinz Graalfs    event->event_pending = false;
3326a444f85SHeinz Graalfs    scon->length = 0;
3336a444f85SHeinz Graalfs    scon->write_errors = 0;
3346a444f85SHeinz Graalfs }
3356a444f85SHeinz Graalfs 
3366a444f85SHeinz Graalfs static Property console_properties[] = {
3376a444f85SHeinz Graalfs     DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr),
3386a444f85SHeinz Graalfs     DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0),
3396a444f85SHeinz Graalfs     DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true),
3406a444f85SHeinz Graalfs     DEFINE_PROP_END_OF_LIST(),
3416a444f85SHeinz Graalfs };
3426a444f85SHeinz Graalfs 
console_class_init(ObjectClass * klass,void * data)3436a444f85SHeinz Graalfs static void console_class_init(ObjectClass *klass, void *data)
3446a444f85SHeinz Graalfs {
3456a444f85SHeinz Graalfs     DeviceClass *dc = DEVICE_CLASS(klass);
3466a444f85SHeinz Graalfs     SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
3476a444f85SHeinz Graalfs 
3484f67d30bSMarc-André Lureau     device_class_set_props(dc, console_properties);
349*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, console_reset);
3506a444f85SHeinz Graalfs     dc->vmsd = &vmstate_sclplmconsole;
3516a444f85SHeinz Graalfs     ec->init = console_init;
3526a444f85SHeinz Graalfs     ec->get_send_mask = send_mask;
3536a444f85SHeinz Graalfs     ec->get_receive_mask = receive_mask;
3546a444f85SHeinz Graalfs     ec->can_handle_event = can_handle_event;
3556a444f85SHeinz Graalfs     ec->read_event_data = read_event_data;
3566a444f85SHeinz Graalfs     ec->write_event_data = write_event_data;
357183f6b8dSCornelia Huck     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
3586a444f85SHeinz Graalfs }
3596a444f85SHeinz Graalfs 
3606a444f85SHeinz Graalfs static const TypeInfo sclp_console_info = {
3611a3bae79SEduardo Habkost     .name          = TYPE_SCLPLM_CONSOLE,
3626a444f85SHeinz Graalfs     .parent        = TYPE_SCLP_EVENT,
3636a444f85SHeinz Graalfs     .instance_size = sizeof(SCLPConsoleLM),
3646a444f85SHeinz Graalfs     .class_init    = console_class_init,
3656a444f85SHeinz Graalfs     .class_size    = sizeof(SCLPEventClass),
3666a444f85SHeinz Graalfs };
3676a444f85SHeinz Graalfs 
register_types(void)3686a444f85SHeinz Graalfs static void register_types(void)
3696a444f85SHeinz Graalfs {
3706a444f85SHeinz Graalfs     type_register_static(&sclp_console_info);
3716a444f85SHeinz Graalfs }
3726a444f85SHeinz Graalfs 
3736a444f85SHeinz Graalfs type_init(register_types)
374