xref: /openbmc/qemu/hw/char/sclpconsole-lm.c (revision 1ffed98f244bd005aef053be968e2ed939e91396)
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 "hw/qdev.h"
186a444f85SHeinz Graalfs #include "qemu/thread.h"
196a444f85SHeinz Graalfs #include "qemu/error-report.h"
204d43a603SMarc-André Lureau #include "chardev/char-fe.h"
216a444f85SHeinz Graalfs 
226a444f85SHeinz Graalfs #include "hw/s390x/sclp.h"
236a444f85SHeinz Graalfs #include "hw/s390x/event-facility.h"
246a444f85SHeinz Graalfs #include "hw/s390x/ebcdic.h"
256a444f85SHeinz Graalfs 
266a444f85SHeinz Graalfs #define SIZE_BUFFER 4096
276a444f85SHeinz Graalfs #define NEWLINE     "\n"
286a444f85SHeinz Graalfs 
296a444f85SHeinz Graalfs typedef struct OprtnsCommand {
306a444f85SHeinz Graalfs     EventBufferHeader header;
316a444f85SHeinz Graalfs     MDMSU message_unit;
326a444f85SHeinz Graalfs     char data[0];
336a444f85SHeinz Graalfs } QEMU_PACKED OprtnsCommand;
346a444f85SHeinz Graalfs 
356a444f85SHeinz Graalfs /* max size for line-mode data in 4K SCCB page */
366a444f85SHeinz Graalfs #define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand))
376a444f85SHeinz Graalfs 
386a444f85SHeinz Graalfs typedef struct SCLPConsoleLM {
396a444f85SHeinz Graalfs     SCLPEvent event;
40becdfa00SMarc-André Lureau     CharBackend chr;
416a444f85SHeinz Graalfs     bool echo;                  /* immediate echo of input if true        */
426a444f85SHeinz Graalfs     uint32_t write_errors;      /* errors writing to char layer           */
436a444f85SHeinz Graalfs     uint32_t length;            /* length of byte stream in buffer        */
446a444f85SHeinz Graalfs     uint8_t buf[SIZE_CONSOLE_BUFFER];
456a444f85SHeinz Graalfs } SCLPConsoleLM;
466a444f85SHeinz Graalfs 
47e563c59bSxiaoqiang zhao #define TYPE_SCLPLM_CONSOLE "sclplmconsole"
48e563c59bSxiaoqiang zhao #define SCLPLM_CONSOLE(obj) \
49e563c59bSxiaoqiang zhao     OBJECT_CHECK(SCLPConsoleLM, (obj), TYPE_SCLPLM_CONSOLE)
50e563c59bSxiaoqiang zhao 
516a444f85SHeinz Graalfs /*
526a444f85SHeinz Graalfs *  Character layer call-back functions
536a444f85SHeinz Graalfs  *
546a444f85SHeinz Graalfs  * Allow 1 character at a time
556a444f85SHeinz Graalfs  *
566a444f85SHeinz Graalfs  * Accumulate bytes from character layer in console buffer,
576a444f85SHeinz Graalfs  * event_pending is set when a newline character is encountered
586a444f85SHeinz Graalfs  *
596a444f85SHeinz Graalfs  * The maximum command line length is limited by the maximum
60b3191432SHeinz Graalfs  * space available in an SCCB. Line mode console input is sent
61b3191432SHeinz Graalfs  * truncated to the guest in case it doesn't fit into the SCCB.
626a444f85SHeinz Graalfs  */
636a444f85SHeinz Graalfs 
646a444f85SHeinz Graalfs static int chr_can_read(void *opaque)
656a444f85SHeinz Graalfs {
666a444f85SHeinz Graalfs     SCLPConsoleLM *scon = opaque;
676a444f85SHeinz Graalfs 
686a444f85SHeinz Graalfs     if (scon->event.event_pending) {
696a444f85SHeinz Graalfs         return 0;
706a444f85SHeinz Graalfs     }
71b3191432SHeinz Graalfs     return 1;
726a444f85SHeinz Graalfs }
736a444f85SHeinz Graalfs 
744f3ed190SChristian Borntraeger static void chr_read(void *opaque, const uint8_t *buf, int size)
756a444f85SHeinz Graalfs {
764f3ed190SChristian Borntraeger     SCLPConsoleLM *scon = opaque;
774f3ed190SChristian Borntraeger 
786a444f85SHeinz Graalfs     assert(size == 1);
796a444f85SHeinz Graalfs 
806a444f85SHeinz Graalfs     if (*buf == '\r' || *buf == '\n') {
816a444f85SHeinz Graalfs         scon->event.event_pending = true;
824f3ed190SChristian Borntraeger         sclp_service_interrupt(0);
836a444f85SHeinz Graalfs         return;
846a444f85SHeinz Graalfs     }
85b3191432SHeinz Graalfs     if (scon->length == SIZE_CONSOLE_BUFFER) {
86b3191432SHeinz Graalfs         /* Eat the character, but still process CR and LF.  */
87b3191432SHeinz Graalfs         return;
88b3191432SHeinz Graalfs     }
896a444f85SHeinz Graalfs     scon->buf[scon->length] = *buf;
906a444f85SHeinz Graalfs     scon->length += 1;
916a444f85SHeinz Graalfs     if (scon->echo) {
926ab3fc32SDaniel P. Berrange         /* XXX this blocks entire thread. Rewrite to use
936ab3fc32SDaniel P. Berrange          * qemu_chr_fe_write and background I/O callbacks */
945345fdb4SMarc-André Lureau         qemu_chr_fe_write_all(&scon->chr, buf, size);
956a444f85SHeinz Graalfs     }
966a444f85SHeinz Graalfs }
976a444f85SHeinz Graalfs 
986a444f85SHeinz Graalfs /* functions to be called by event facility */
996a444f85SHeinz Graalfs 
1006a444f85SHeinz Graalfs static bool can_handle_event(uint8_t type)
1016a444f85SHeinz Graalfs {
1026a444f85SHeinz Graalfs     return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD;
1036a444f85SHeinz Graalfs }
1046a444f85SHeinz Graalfs 
105*1ffed98fSClaudio Imbrenda static sccb_mask_t send_mask(void)
1066a444f85SHeinz Graalfs {
1076a444f85SHeinz Graalfs     return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD;
1086a444f85SHeinz Graalfs }
1096a444f85SHeinz Graalfs 
110*1ffed98fSClaudio Imbrenda static sccb_mask_t receive_mask(void)
1116a444f85SHeinz Graalfs {
1126a444f85SHeinz Graalfs     return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD;
1136a444f85SHeinz Graalfs }
1146a444f85SHeinz Graalfs 
1156a444f85SHeinz Graalfs /*
1166a444f85SHeinz Graalfs  * Triggered by SCLP's read_event_data
1176a444f85SHeinz Graalfs  * - convert ASCII byte stream to EBCDIC and
1186a444f85SHeinz Graalfs  * - copy converted data into provided (SCLP) buffer
1196a444f85SHeinz Graalfs  */
1206a444f85SHeinz Graalfs static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
1216a444f85SHeinz Graalfs                             int avail)
1226a444f85SHeinz Graalfs {
1236a444f85SHeinz Graalfs     int len;
1246a444f85SHeinz Graalfs 
125e563c59bSxiaoqiang zhao     SCLPConsoleLM *cons = SCLPLM_CONSOLE(event);
1266a444f85SHeinz Graalfs 
1276a444f85SHeinz Graalfs     len = cons->length;
1286a444f85SHeinz Graalfs     /* data need to fit into provided SCLP buffer */
1296a444f85SHeinz Graalfs     if (len > avail) {
1306a444f85SHeinz Graalfs         return 1;
1316a444f85SHeinz Graalfs     }
1326a444f85SHeinz Graalfs 
1336a444f85SHeinz Graalfs     ebcdic_put(buf, (char *)&cons->buf, len);
1346a444f85SHeinz Graalfs     *size = len;
1356a444f85SHeinz Graalfs     cons->length = 0;
1366a444f85SHeinz Graalfs     /* data provided and no more data pending */
1376a444f85SHeinz Graalfs     event->event_pending = false;
13887f2eff0SHeinz Graalfs     qemu_notify_event();
1396a444f85SHeinz Graalfs     return 0;
1406a444f85SHeinz Graalfs }
1416a444f85SHeinz Graalfs 
1426a444f85SHeinz Graalfs static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
1436a444f85SHeinz Graalfs                            int *slen)
1446a444f85SHeinz Graalfs {
1456a444f85SHeinz Graalfs     int avail, rc;
1466a444f85SHeinz Graalfs     size_t src_len;
1476a444f85SHeinz Graalfs     uint8_t *to;
1486a444f85SHeinz Graalfs     OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr;
1496a444f85SHeinz Graalfs 
1506a444f85SHeinz Graalfs     if (!event->event_pending) {
1516a444f85SHeinz Graalfs         /* no data pending */
1526a444f85SHeinz Graalfs         return 0;
1536a444f85SHeinz Graalfs     }
1546a444f85SHeinz Graalfs 
1556a444f85SHeinz Graalfs     to = (uint8_t *)&oc->data;
1566a444f85SHeinz Graalfs     avail = *slen - sizeof(OprtnsCommand);
1576a444f85SHeinz Graalfs     rc = get_console_data(event, to, &src_len, avail);
1586a444f85SHeinz Graalfs     if (rc) {
1596a444f85SHeinz Graalfs         /* data didn't fit, try next SCCB */
1606a444f85SHeinz Graalfs         return 1;
1616a444f85SHeinz Graalfs     }
1626a444f85SHeinz Graalfs 
1636a444f85SHeinz Graalfs     oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU;
1646a444f85SHeinz Graalfs     oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU));
1656a444f85SHeinz Graalfs 
1666a444f85SHeinz Graalfs     oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU;
1676a444f85SHeinz Graalfs     oc->message_unit.cpmsu.length =
1686a444f85SHeinz Graalfs         cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector));
1696a444f85SHeinz Graalfs 
1706a444f85SHeinz Graalfs     oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD;
1716a444f85SHeinz Graalfs     oc->message_unit.text_command.length =
1726a444f85SHeinz Graalfs         cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector)));
1736a444f85SHeinz Graalfs 
1746a444f85SHeinz Graalfs     oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG;
1756a444f85SHeinz Graalfs     oc->message_unit.self_def_text_message.length =
1766a444f85SHeinz Graalfs         cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector)));
1776a444f85SHeinz Graalfs 
1786a444f85SHeinz Graalfs     oc->message_unit.text_message.key = GDS_KEY_TEXTMSG;
1796a444f85SHeinz Graalfs     oc->message_unit.text_message.length =
1806a444f85SHeinz Graalfs         cpu_to_be16(sizeof(GdsSubvector) + src_len);
1816a444f85SHeinz Graalfs 
1826a444f85SHeinz Graalfs     oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len);
1836a444f85SHeinz Graalfs     oc->header.type = SCLP_EVENT_OPRTNS_COMMAND;
1846a444f85SHeinz Graalfs     *slen = avail - src_len;
1856a444f85SHeinz Graalfs 
1866a444f85SHeinz Graalfs     return 1;
1876a444f85SHeinz Graalfs }
1886a444f85SHeinz Graalfs 
1896a444f85SHeinz Graalfs /*
1906a444f85SHeinz Graalfs  * Triggered by SCLP's write_event_data
1916a444f85SHeinz Graalfs  *  - write console data to character layer
1926a444f85SHeinz Graalfs  *  returns < 0 if an error occurred
1936a444f85SHeinz Graalfs  */
1946a444f85SHeinz Graalfs static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
1956a444f85SHeinz Graalfs {
196e563c59bSxiaoqiang zhao     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
1976a444f85SHeinz Graalfs 
19830650701SAnton Nefedov     if (!qemu_chr_fe_backend_connected(&scon->chr)) {
1996a444f85SHeinz Graalfs         /* If there's no backend, we can just say we consumed all data. */
2006a444f85SHeinz Graalfs         return len;
2016a444f85SHeinz Graalfs     }
2026a444f85SHeinz Graalfs 
2037983e829SDaniel P. Berrange     /* XXX this blocks entire thread. Rewrite to use
2047983e829SDaniel P. Berrange      * qemu_chr_fe_write and background I/O callbacks */
2055345fdb4SMarc-André Lureau     return qemu_chr_fe_write_all(&scon->chr, buf, len);
2066a444f85SHeinz Graalfs }
2076a444f85SHeinz Graalfs 
2086a444f85SHeinz Graalfs static int process_mdb(SCLPEvent *event, MDBO *mdbo)
2096a444f85SHeinz Graalfs {
2106a444f85SHeinz Graalfs     int rc;
2116a444f85SHeinz Graalfs     int len;
2126a444f85SHeinz Graalfs     uint8_t buffer[SIZE_BUFFER];
2136a444f85SHeinz Graalfs 
2146a444f85SHeinz Graalfs     len = be16_to_cpu(mdbo->length);
2156a444f85SHeinz Graalfs     len -= sizeof(mdbo->length) + sizeof(mdbo->type)
2166a444f85SHeinz Graalfs             + sizeof(mdbo->mto.line_type_flags)
2176a444f85SHeinz Graalfs             + sizeof(mdbo->mto.alarm_control)
2186a444f85SHeinz Graalfs             + sizeof(mdbo->mto._reserved);
2196a444f85SHeinz Graalfs 
2206a444f85SHeinz Graalfs     assert(len <= SIZE_BUFFER);
2216a444f85SHeinz Graalfs 
2226a444f85SHeinz Graalfs     /* convert EBCDIC SCLP contents to ASCII console message */
2236a444f85SHeinz Graalfs     ascii_put(buffer, mdbo->mto.message, len);
2246a444f85SHeinz Graalfs     rc = write_console_data(event, (uint8_t *)NEWLINE, 1);
2256a444f85SHeinz Graalfs     if (rc < 0) {
2266a444f85SHeinz Graalfs         return rc;
2276a444f85SHeinz Graalfs     }
2286a444f85SHeinz Graalfs     return write_console_data(event, buffer, len);
2296a444f85SHeinz Graalfs }
2306a444f85SHeinz Graalfs 
2316a444f85SHeinz Graalfs static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
2326a444f85SHeinz Graalfs {
2336a444f85SHeinz Graalfs     int len;
2346a444f85SHeinz Graalfs     int written;
2356a444f85SHeinz Graalfs     int errors = 0;
2366a444f85SHeinz Graalfs     MDBO *mdbo;
2376a444f85SHeinz Graalfs     SclpMsg *data = (SclpMsg *) ebh;
238e563c59bSxiaoqiang zhao     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
2396a444f85SHeinz Graalfs 
2406a444f85SHeinz Graalfs     len = be16_to_cpu(data->mdb.header.length);
2416a444f85SHeinz Graalfs     if (len < sizeof(data->mdb.header)) {
2426a444f85SHeinz Graalfs         return SCLP_RC_INCONSISTENT_LENGTHS;
2436a444f85SHeinz Graalfs     }
2446a444f85SHeinz Graalfs     len -= sizeof(data->mdb.header);
2456a444f85SHeinz Graalfs 
2466a444f85SHeinz Graalfs     /* first check message buffers */
2476a444f85SHeinz Graalfs     mdbo = data->mdb.mdbo;
2486a444f85SHeinz Graalfs     while (len > 0) {
2496a444f85SHeinz Graalfs         if (be16_to_cpu(mdbo->length) > len
2506a444f85SHeinz Graalfs                 || be16_to_cpu(mdbo->length) == 0) {
2516a444f85SHeinz Graalfs             return SCLP_RC_INCONSISTENT_LENGTHS;
2526a444f85SHeinz Graalfs         }
2536a444f85SHeinz Graalfs         len -= be16_to_cpu(mdbo->length);
2546a444f85SHeinz Graalfs         mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
2556a444f85SHeinz Graalfs     }
2566a444f85SHeinz Graalfs 
2576a444f85SHeinz Graalfs     /* then execute */
2586a444f85SHeinz Graalfs     len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header);
2596a444f85SHeinz Graalfs     mdbo = data->mdb.mdbo;
2606a444f85SHeinz Graalfs     while (len > 0) {
2616a444f85SHeinz Graalfs         switch (be16_to_cpu(mdbo->type)) {
2626a444f85SHeinz Graalfs         case MESSAGE_TEXT:
2636a444f85SHeinz Graalfs             /* message text object */
2646a444f85SHeinz Graalfs             written = process_mdb(event, mdbo);
2656a444f85SHeinz Graalfs             if (written < 0) {
2666a444f85SHeinz Graalfs                 /* character layer error */
2676a444f85SHeinz Graalfs                 errors++;
2686a444f85SHeinz Graalfs             }
2696a444f85SHeinz Graalfs             break;
2706a444f85SHeinz Graalfs         default: /* ignore */
2716a444f85SHeinz Graalfs             break;
2726a444f85SHeinz Graalfs         }
2736a444f85SHeinz Graalfs         len -= be16_to_cpu(mdbo->length);
2746a444f85SHeinz Graalfs         mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
2756a444f85SHeinz Graalfs     }
2766a444f85SHeinz Graalfs     if (errors) {
2776a444f85SHeinz Graalfs         scon->write_errors += errors;
2786a444f85SHeinz Graalfs     }
2796a444f85SHeinz Graalfs     data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED;
2806a444f85SHeinz Graalfs 
2816a444f85SHeinz Graalfs     return SCLP_RC_NORMAL_COMPLETION;
2826a444f85SHeinz Graalfs }
2836a444f85SHeinz Graalfs 
2846a444f85SHeinz Graalfs /* functions for live migration */
2856a444f85SHeinz Graalfs 
2866a444f85SHeinz Graalfs static const VMStateDescription vmstate_sclplmconsole = {
2876a444f85SHeinz Graalfs     .name = "sclplmconsole",
2886a444f85SHeinz Graalfs     .version_id = 0,
2896a444f85SHeinz Graalfs     .minimum_version_id = 0,
2906a444f85SHeinz Graalfs     .fields = (VMStateField[]) {
2916a444f85SHeinz Graalfs         VMSTATE_BOOL(event.event_pending, SCLPConsoleLM),
2926a444f85SHeinz Graalfs         VMSTATE_UINT32(write_errors, SCLPConsoleLM),
2936a444f85SHeinz Graalfs         VMSTATE_UINT32(length, SCLPConsoleLM),
2946a444f85SHeinz Graalfs         VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER),
2956a444f85SHeinz Graalfs         VMSTATE_END_OF_LIST()
2966a444f85SHeinz Graalfs      }
2976a444f85SHeinz Graalfs };
2986a444f85SHeinz Graalfs 
2996a444f85SHeinz Graalfs /* qemu object creation and initialization functions */
3006a444f85SHeinz Graalfs 
3016a444f85SHeinz Graalfs /* tell character layer our call-back functions */
3026a444f85SHeinz Graalfs 
3036a444f85SHeinz Graalfs static int console_init(SCLPEvent *event)
3046a444f85SHeinz Graalfs {
3056a444f85SHeinz Graalfs     static bool console_available;
3066a444f85SHeinz Graalfs 
307e563c59bSxiaoqiang zhao     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
3086a444f85SHeinz Graalfs 
3096a444f85SHeinz Graalfs     if (console_available) {
3106a444f85SHeinz Graalfs         error_report("Multiple line-mode operator consoles are not supported");
3116a444f85SHeinz Graalfs         return -1;
3126a444f85SHeinz Graalfs     }
3136a444f85SHeinz Graalfs     console_available = true;
3146a444f85SHeinz Graalfs 
3155345fdb4SMarc-André Lureau     qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
31681517ba3SAnton Nefedov                              chr_read, NULL, NULL, scon, NULL, true);
3176a444f85SHeinz Graalfs 
3186a444f85SHeinz Graalfs     return 0;
3196a444f85SHeinz Graalfs }
3206a444f85SHeinz Graalfs 
3216a444f85SHeinz Graalfs static void console_reset(DeviceState *dev)
3226a444f85SHeinz Graalfs {
3236a444f85SHeinz Graalfs    SCLPEvent *event = SCLP_EVENT(dev);
324e563c59bSxiaoqiang zhao    SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
3256a444f85SHeinz Graalfs 
3266a444f85SHeinz Graalfs    event->event_pending = false;
3276a444f85SHeinz Graalfs    scon->length = 0;
3286a444f85SHeinz Graalfs    scon->write_errors = 0;
3296a444f85SHeinz Graalfs }
3306a444f85SHeinz Graalfs 
3316a444f85SHeinz Graalfs static Property console_properties[] = {
3326a444f85SHeinz Graalfs     DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr),
3336a444f85SHeinz Graalfs     DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0),
3346a444f85SHeinz Graalfs     DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true),
3356a444f85SHeinz Graalfs     DEFINE_PROP_END_OF_LIST(),
3366a444f85SHeinz Graalfs };
3376a444f85SHeinz Graalfs 
3386a444f85SHeinz Graalfs static void console_class_init(ObjectClass *klass, void *data)
3396a444f85SHeinz Graalfs {
3406a444f85SHeinz Graalfs     DeviceClass *dc = DEVICE_CLASS(klass);
3416a444f85SHeinz Graalfs     SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
3426a444f85SHeinz Graalfs 
3436a444f85SHeinz Graalfs     dc->props = console_properties;
3446a444f85SHeinz Graalfs     dc->reset = console_reset;
3456a444f85SHeinz Graalfs     dc->vmsd = &vmstate_sclplmconsole;
3466a444f85SHeinz Graalfs     ec->init = console_init;
3476a444f85SHeinz Graalfs     ec->get_send_mask = send_mask;
3486a444f85SHeinz Graalfs     ec->get_receive_mask = receive_mask;
3496a444f85SHeinz Graalfs     ec->can_handle_event = can_handle_event;
3506a444f85SHeinz Graalfs     ec->read_event_data = read_event_data;
3516a444f85SHeinz Graalfs     ec->write_event_data = write_event_data;
352183f6b8dSCornelia Huck     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
3536a444f85SHeinz Graalfs }
3546a444f85SHeinz Graalfs 
3556a444f85SHeinz Graalfs static const TypeInfo sclp_console_info = {
3566a444f85SHeinz Graalfs     .name          = "sclplmconsole",
3576a444f85SHeinz Graalfs     .parent        = TYPE_SCLP_EVENT,
3586a444f85SHeinz Graalfs     .instance_size = sizeof(SCLPConsoleLM),
3596a444f85SHeinz Graalfs     .class_init    = console_class_init,
3606a444f85SHeinz Graalfs     .class_size    = sizeof(SCLPEventClass),
3616a444f85SHeinz Graalfs };
3626a444f85SHeinz Graalfs 
3636a444f85SHeinz Graalfs static void register_types(void)
3646a444f85SHeinz Graalfs {
3656a444f85SHeinz Graalfs     type_register_static(&sclp_console_info);
3666a444f85SHeinz Graalfs }
3676a444f85SHeinz Graalfs 
3686a444f85SHeinz Graalfs type_init(register_types)
369