qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support


From: Jens Freimann
Subject: [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support
Date: Wed, 6 Jun 2012 14:05:22 +0200

From: Heinz Graalfs <address@hidden>

Adds console support (in vt220 mode).
In order to run qemu exploiting the SCLP's console functionality in vt220 mode
the user has to specify the following console related parameters:

 -chardev stdio,id=charconsole0 -device 
sclpconsole,chardev=charconsole0,id=console0

Signed-off-by: Heinz Graalfs <address@hidden>
Signed-off-by: Jens Freimann <address@hidden>
---
 hw/s390-event-facility.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/s390-event-facility.h |    8 ++
 hw/s390-sclp.c           |  177 ++++++++++++++++++++++++++++++++++++++-
 hw/s390-sclp.h           |   22 ++++-
 sysemu.h                 |    1 +
 target-s390x/op_helper.c |    6 ++
 vl.c                     |   41 +++++++++
 7 files changed, 460 insertions(+), 4 deletions(-)

diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
index b8106a6..cfa5dd4 100644
--- a/hw/s390-event-facility.c
+++ b/hw/s390-event-facility.c
@@ -16,6 +16,11 @@
 #include "s390-sclp.h"
 #include "s390-event-facility.h"
 
+qemu_irq sclp_read_vt220;
+
+static int size_buffer = 4096;
+static char *sclp_console_data_vt220;
+
 struct SCLPDevice {
     const char *name;
     bool vm_running;
@@ -224,9 +229,213 @@ static TypeInfo sclp_quiesce_info = {
     .class_init    = sclpef_quiesce_class_init,
 };
 
+/* ----------- SCLP VT220 console ------------ */
+
+static void s390_signal_read_vt220(void *opaque, int n, int level)
+{
+    sclp_enable_signal_read_vt220();
+    sclp_service_interrupt(opaque, 0);
+}
+
+static void sclpef_set_console(SCLPEvent *event)
+{
+    if (event->id == ID_VT220) {
+        sclp_read_vt220 = *qemu_allocate_irqs(s390_signal_read_vt220,
+            event->evt_fac->opaque, 1);
+    }
+}
+
+void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf)
+{
+    DeviceState *dev;
+    SCLPEventFacility *event_facility;
+    static SCLPEvent *event;
+    static SCLPEventClass *cons;
+
+    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
+
+    if (!cons) {
+        QTAILQ_FOREACH(dev, &event_facility->sbus.qbus.children, sibling) {
+            event = (SCLPEvent *) dev;
+            if (event->id == ID_VT220) {
+                cons = SCLP_EVENT_GET_CLASS(event);
+                assert(cons->have_data);
+                break;
+            }
+        }
+    }
+    if (cons) {
+        cons->have_data(event, (const uint8_t *)buf, strlen(buf));
+    }
+}
+
+char *sclpef_get_console_data_vt220(SCLPDevice *sdev)
+{
+    DeviceState *dev;
+    SCLPEventFacility *event_facility;
+    SCLPEvent *event = NULL;
+    static SCLPEventClass *cons;
+
+    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
+
+    if (!cons) {
+        QTAILQ_FOREACH(dev, &event_facility->sbus.qbus.children, sibling) {
+            event = (SCLPEvent *) dev;
+            if (event->id == ID_VT220) {
+                cons = SCLP_EVENT_GET_CLASS(event);
+                assert(cons->get_data);
+                break;
+            }
+        }
+    }
+    if (cons) {
+        return cons->get_data();
+    }
+    return NULL;
+}
+
+static char *console_data_vt220(void)
+{
+    return sclp_console_data_vt220;
+}
+
+static ssize_t flush_buf(SCLPEvent *event, const uint8_t *buf, size_t len)
+{
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+    ssize_t ret;
+
+    if (!scon->chr) {
+        /* If there's no backend, we can just say we consumed all data. */
+        return len;
+    }
+
+    ret = qemu_chr_fe_write(scon->chr, buf, len);
+
+    if (ret < 0) {
+        /* see virtio-console comments */
+        ret = 0;
+    }
+
+    return ret;
+}
+
+static void guest_open(SCLPEvent *event)
+{
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+    if (!scon->chr) {
+        return;
+    }
+    qemu_chr_fe_open(scon->chr);
+}
+
+static void guest_close(SCLPEvent *event)
+{
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+    if (!scon->chr) {
+        return;
+    }
+    qemu_chr_fe_close(scon->chr);
+}
+
+static int chr_can_read(void *opaque)
+{
+    return 1;
+}
+
+static void chr_read_vt220(void *opaque, const uint8_t *buf, int size)
+{
+    char *offset;
+
+    if (!sclp_console_data_vt220) {
+        size_buffer = 2 * size;
+        sclp_console_data_vt220 = malloc(size_buffer);
+    }
+    if (size_buffer < size + 1) {
+        free(sclp_console_data_vt220);
+        size_buffer = 2 * size;
+        sclp_console_data_vt220 = malloc(size_buffer);
+    }
+    offset = sclp_console_data_vt220;
+    if (offset) {
+        memcpy(offset, buf, size);
+        offset += size;
+        *offset = '\0';
+        qemu_irq_raise(sclp_read_vt220);
+    } else {
+        size_buffer = 0;
+    }
+}
+
+static void chr_event(void *opaque, int event)
+{
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        if (!sclp_console_data_vt220) {
+            sclp_console_data_vt220 = malloc(size_buffer);
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        break;
+    }
+}
+
+static unsigned int send_mask_vt220(void)
+{
+    return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+static unsigned int receive_mask_vt220(void)
+{
+    return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+static int sclpconsole_initfn_vt220(SCLPEvent *event)
+{
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+    event->id = ID_VT220;
+    sclpef_set_console(event);
+    if (scon->chr) {
+        qemu_chr_add_handlers(scon->chr, chr_can_read,
+                chr_read_vt220, chr_event, scon);
+    }
+
+    return 0;
+}
+
+static Property sclpconsole_properties[] = {
+    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sclpconsole_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
+
+    k->init = sclpconsole_initfn_vt220;
+    k->have_data = flush_buf;
+    k->guest_open = guest_open;
+    k->guest_close = guest_close;
+    k->get_send_mask = send_mask_vt220;
+    k->get_receive_mask = receive_mask_vt220;
+    k->get_data = console_data_vt220;
+    dc->props = sclpconsole_properties;
+}
+
+static TypeInfo sclpconsole_info = {
+    .name          = "sclpconsole",
+    .parent        = TYPE_SCLP_EVENT,
+    .instance_size = sizeof(SCLPConsole),
+    .class_init    = sclpconsole_class_init,
+};
+
 static void sclpef_register_types(void)
 {
     type_register_static(&sclp_event_facility_type_info);
     type_register_static(&sclp_quiesce_info);
+    type_register_static(&sclpconsole_info);
 }
 type_init(sclpef_register_types)
diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
index 40d4049..d6bde7d 100644
--- a/hw/s390-event-facility.h
+++ b/hw/s390-event-facility.h
@@ -14,6 +14,7 @@
 #include "qemu-common.h"
 
 #define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
+#define ID_VT220   SCLP_EVENT_ASCII_CONSOLE_DATA
 
 #define TYPE_SCLP_EVENT "s390-sclp-event-type"
 #define SCLP_EVENT(obj) \
@@ -34,6 +35,11 @@ typedef struct SCLPEventClass {
     int (*exit)(SCLPEvent *event);
     unsigned int (*get_send_mask)(void);
     unsigned int (*get_receive_mask)(void);
+    void (*guest_open)(SCLPEvent *event);
+    void (*guest_close)(SCLPEvent *event);
+    void (*guest_ready)(SCLPEvent *event);
+    ssize_t (*have_data)(SCLPEvent *event, const uint8_t *buf, size_t len);
+    char *(*get_data)(void);
 } SCLPEventClass;
 
 struct SCLPEvent {
@@ -50,5 +56,7 @@ void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
 void sclpef_set_masks(void);
 unsigned int sclpef_send_mask(SCLPDevice *sdev);
 unsigned int sclpef_receive_mask(SCLPDevice *sdev);
+void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf);
+char *sclpef_get_console_data_vt220(SCLPDevice *sdev);
 
 #endif
diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
index 683a709..8f45773 100644
--- a/hw/s390-sclp.c
+++ b/hw/s390-sclp.c
@@ -11,6 +11,11 @@
 #include "hw/s390-sclp.h"
 #include "hw/s390-event-facility.h"
 
+/* input buffer handling */
+#define INP_BUFFER_SIZE 4096
+static int sclp_curr_buf_size;
+static char *sclp_input_vt220;
+
 /* Host capabilites */
 static unsigned int sclp_send_mask;
 static unsigned int sclp_receive_mask;
@@ -21,6 +26,7 @@ static unsigned int sclp_cp_receive_mask;
 
 static int quiesce;
 static int event_pending;
+static int vt220;
 
 int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
 {
@@ -66,6 +72,7 @@ void sclp_enable_signal_quiesce(void)
 {
     quiesce = 1;
     event_pending = 1;
+    vt220 = 0;
 }
 
 static void sclp_set_masks(void)
@@ -81,7 +88,112 @@ static void sclp_set_masks(void)
 
     sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
     sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
- }
+}
+
+static int signal_vt220_event(struct sccb *sccb, int *slen)
+{
+    char *p;
+
+    if (!sclp_input_vt220 || !vt220) {
+        return 0;
+    }
+
+    int l = strlen(sclp_input_vt220);
+
+    if (*slen < sizeof(struct ascii_cons_data_command) + l + 1) {
+        event_pending = 1;
+        return 0;
+    }
+    p = (char *)&sccb->c.read.acd_cmd.data;
+    /* first byte is hex 0 saying an ascii string follows */
+    *p++ = '\0';
+    memmove(p, sclp_input_vt220, l);
+    *sclp_input_vt220 = '\0';
+
+    sccb->c.read.acd_cmd.h.length =
+            cpu_to_be16(sizeof(struct ascii_cons_data_command) + l + 1);
+    sccb->c.read.acd_cmd.h.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
+
+    vt220 = 0;
+    *slen -= sizeof(struct ascii_cons_data_command) + l + 1;
+    return 1;
+}
+
+static char *grow_buffer(int size)
+{
+    char *p = (char *) malloc(size);
+
+    if (!p) {
+        sclp_curr_buf_size = 0;
+        return NULL;
+    }
+    memset(p, '\0', size);
+    sclp_curr_buf_size = size;
+    return p;
+}
+
+static int sclp_write_vt220(struct event_buffer_header *event)
+{
+    int l;
+    char *msg;
+    SCLPS390EventFacility *evt_fac;
+    struct ascii_cons_data_command *ad =
+            (struct ascii_cons_data_command *) event;
+
+    assert(sclp_bus);
+
+    l = event->length - sizeof(struct event_buffer_header);
+    msg = (char *) malloc(l + 1);
+    assert(msg);
+    memset(msg, '\0', l + 1);
+    memmove(msg, ad->data, l);
+
+    evt_fac = sclp_bus->event_facility;
+    sclpef_write_console_vt220(evt_fac->sdev, msg);
+
+    free(msg);
+
+    return SCLP_RC_NORMAL_COMPLETION;
+}
+
+void sclp_enable_signal_read_vt220(void)
+{
+    int len;
+    char *input;
+    SCLPS390EventFacility *evt_fac;
+
+    if (!sclp_bus) {
+        return;
+    }
+    evt_fac = sclp_bus->event_facility;
+
+    assert(evt_fac);
+
+    input = sclpef_get_console_data_vt220(evt_fac->sdev);
+
+    if (!input) {
+        return;
+    }
+
+    vt220 = 1;
+    quiesce = 0;
+    event_pending = 1;
+    len = strlen((char *) input);
+    if (sclp_input_vt220 == NULL) {
+        /* get new buffer */
+        sclp_input_vt220 = grow_buffer(2 * len + 1);
+    } else {
+        if (len >= sclp_curr_buf_size) {
+            /* get larger buffer */
+            char *p = grow_buffer(2 * len + 1);
+            free(sclp_input_vt220);
+            sclp_input_vt220 = p;
+        }
+    }
+    if (sclp_input_vt220) {
+        strcat(sclp_input_vt220, (char *)input);
+    }
+}
 
 int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
 {
@@ -99,7 +211,8 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb 
*sccb)
         break;
     case SCLP_SELECTIVE_READ:
         if (!(sclp_cp_receive_mask & be32_to_cpu(sccb->c.read.mask))) {
-            sccb->h.response_code = 
cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
+            sccb->h.response_code =
+                    cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
             goto out;
         }
         sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
@@ -117,7 +230,12 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb 
*sccb)
             sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
         }
     }
-
+    if (sclp_active_selection_mask & SCLP_EVENT_MASK_MSG_ASCII) {
+        if (signal_vt220_event(sccb, &slen)) {
+            sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
+            sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
+        }
+    }
     if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
         sccb->h.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE;
         sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
@@ -127,6 +245,59 @@ out:
     return 0;
 }
 
+int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb)
+{
+    struct event_buffer_header *event;
+    int slen;
+    unsigned elen = 0;
+
+    if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) {
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
+        goto out;
+    }
+    if (be16_to_cpu(sccb->h.length) < 8) {
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
+        goto out;
+    }
+
+    /* first check the sum of all events */
+    event = &sccb->c.event;
+    for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
+         slen > 0; slen -= elen) {
+        elen = be16_to_cpu(event->length);
+        if (elen < sizeof(*event) || elen > slen) {
+            sccb->h.response_code =
+                    cpu_to_be16(SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR);
+            goto out;
+        }
+        event = (void *) event + elen;
+    }
+    if (slen) {
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INCONSISTENT_LENGTHS);
+        goto out;
+    }
+
+    /* the execute */
+    event = &sccb->c.event;
+    for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
+         slen > 0; slen -= elen) {
+        elen = be16_to_cpu(event->length);
+        switch (event->type) {
+        case SCLP_EVENT_ASCII_CONSOLE_DATA:
+            sccb->h.response_code = cpu_to_be16(sclp_write_vt220(event));
+            break;
+        default:
+            sccb->h.response_code = SCLP_RC_INVALID_FUNCTION;
+            break;
+        }
+        event = (void *) event + elen;
+    }
+    sccb->h.response_code = SCLP_RC_NORMAL_COMPLETION;
+
+out:
+    return 0;
+}
+
 int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
 {
     /* Attention: We assume that Linux uses 4-byte masks, what it actually
diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
index f61421b..c86bca8 100644
--- a/hw/s390-sclp.h
+++ b/hw/s390-sclp.h
@@ -7,6 +7,8 @@
 /* SCLP command codes */
 #define SCLP_CMDW_READ_SCP_INFO                 0x00020001
 #define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
+#define SCLP_CMD_READ_EVENT_DATA                0x00770005
+#define SCLP_CMD_WRITE_EVENT_DATA               0x00760005
 #define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
 
 /* SCLP response codes */
@@ -20,11 +22,12 @@
 #define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
 
 /* SCLP event types */
+#define SCLP_EVENT_ASCII_CONSOLE_DATA           0x1a
 #define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
 
 /* SCLP event masks */
 #define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
-#define SCLP_EVENT_MASK_MSG                     0x40000000
+#define SCLP_EVENT_MASK_MSG_ASCII               0x00000040
 
 #define SCLP_UNCONDITIONAL_READ                 0x00
 #define SCLP_SELECTIVE_READ                     0x01
@@ -44,6 +47,13 @@ struct write_event_mask {
     uint32_t receive_mask;
 } __attribute__((packed));
 
+struct mdb_header {
+    uint16_t length;
+    uint16_t type;
+    uint32_t tag;
+    uint32_t revision_code;
+} __attribute__((packed));
+
 struct event_buffer_header {
     uint16_t length;
     uint8_t  type;
@@ -58,9 +68,15 @@ struct signal_quiesce {
     uint8_t unit;
 } __attribute__((packed));
 
+struct ascii_cons_data_command {
+    struct event_buffer_header h;
+    char data[0];
+} __attribute__((packed));
+
 struct read_event_data {
     union {
         struct signal_quiesce quiesce;
+        struct ascii_cons_data_command acd_cmd;
         uint32_t mask;
     };
 } __attribute__((packed));
@@ -84,15 +100,19 @@ struct sccb {
     struct sccb_header h;
     union {
         struct read_info_sccb read_info;
+        struct event_buffer_header event;
         struct read_event_data read;
+        struct ascii_cons_data_command acd_cmd;
         struct write_event_mask we_mask;
         char data[SCCB_DATA_LEN];
     } c;
  } __attribute__((packed));
 
 void sclp_enable_signal_quiesce(void);
+void sclp_enable_signal_read_vt220(void);
 int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
 int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
+int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb);
 int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
 void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
 
diff --git a/sysemu.h b/sysemu.h
index bc2c788..b4d399c 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -62,6 +62,7 @@ int qemu_powerdown_requested(void);
 void qemu_system_killed(int signal, pid_t pid);
 void qemu_kill_report(void);
 extern qemu_irq qemu_system_powerdown;
+extern qemu_irq sclp_read_vt220;
 void qemu_system_reset(bool report);
 
 void qemu_add_exit_notifier(Notifier *notify);
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 3e5eff4..4d49472 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -2391,6 +2391,12 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, 
uint64_t code)
         case SCLP_CMDW_READ_SCP_INFO_FORCED:
             r = sclp_read_info(env, &work_sccb);
             break;
+        case SCLP_CMD_READ_EVENT_DATA:
+            r = sclp_read_event_data(env, &work_sccb);
+            break;
+        case SCLP_CMD_WRITE_EVENT_DATA:
+            r = sclp_write_event_data(env, &work_sccb);
+            break;
         case SCLP_CMD_WRITE_EVENT_MASK:
             r = sclp_write_event_mask(env, &work_sccb);
             break;
diff --git a/vl.c b/vl.c
index 23ab3a3..aba7ab0 100644
--- a/vl.c
+++ b/vl.c
@@ -174,6 +174,7 @@ int main(int argc, char **argv)
 #define DEFAULT_RAM_SIZE 128
 
 #define MAX_VIRTIO_CONSOLES 1
+#define MAX_SCLP_CONSOLES   1
 
 static const char *data_dir;
 const char *bios_name = NULL;
@@ -201,6 +202,7 @@ int no_quit = 0;
 CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
+CharDriverState *sclpcon_hds[MAX_SCLP_CONSOLES];
 int win2k_install_hack = 0;
 int usb_enabled = 0;
 int singlestep = 0;
@@ -274,6 +276,8 @@ static int default_floppy = 1;
 static int default_cdrom = 1;
 static int default_sdcard = 1;
 static int default_vga = 1;
+static int default_sclpcon = 1;
+static int default_loader = 1;
 
 static struct {
     const char *driver;
@@ -295,6 +299,8 @@ static struct {
     { .driver = "isa-cirrus-vga",       .flag = &default_vga       },
     { .driver = "vmware-svga",          .flag = &default_vga       },
     { .driver = "qxl-vga",              .flag = &default_vga       },
+    { .driver = "s390-sclp",            .flag = &default_sclpcon   },
+    { .driver = "s390-ipl",             .flag = &default_loader    },
 };
 
 static void res_free(void)
@@ -1942,6 +1948,7 @@ struct device_config {
         DEV_VIRTCON,   /* -virtioconsole */
         DEV_DEBUGCON,  /* -debugcon */
         DEV_GDB,       /* -gdb, -s */
+        DEV_SCLPCON,   /* sclp console */
     } type;
     const char *cmdline;
     Location loc;
@@ -2058,6 +2065,36 @@ static int virtcon_parse(const char *devname)
     return 0;
 }
 
+static int sclpcon_parse(const char *devname)
+{
+    QemuOptsList *device = qemu_find_opts("device");
+    static int index;
+    char label[32];
+    QemuOpts *dev_opts;
+
+    if (strcmp(devname, "none") == 0)
+        return 0;
+    if (index == MAX_SCLP_CONSOLES) {
+        fprintf(stderr, "qemu: too many sclp consoles\n");
+        exit(1);
+    }
+
+    dev_opts = qemu_opts_create(device, NULL, 0);
+    qemu_opt_set(dev_opts, "driver", "sclpconsole");
+
+    snprintf(label, sizeof(label), "sclpcon%d", index);
+    sclpcon_hds[index] = qemu_chr_new(label, devname, NULL);
+    if (!sclpcon_hds[index]) {
+        fprintf(stderr, "qemu: could not open sclp console '%s': %s\n",
+                devname, strerror(errno));
+        return -1;
+    }
+    qemu_opt_set(dev_opts, "chardev", label);
+
+    index++;
+    return 0;
+}
+
 static int debugcon_parse(const char *devname)
 {   
     QemuOpts *opts;
@@ -3304,6 +3341,8 @@ int main(int argc, char **argv, char **envp)
             add_device_config(DEV_SERIAL, "mon:stdio");
         } else if (default_virtcon && default_monitor) {
             add_device_config(DEV_VIRTCON, "mon:stdio");
+        } else if (default_sclpcon && default_monitor) {
+            add_device_config(DEV_SCLPCON, "mon:stdio");
         } else {
             if (default_serial)
                 add_device_config(DEV_SERIAL, "stdio");
@@ -3491,6 +3530,8 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0)
         exit(1);
+    if (foreach_device_config(DEV_SCLPCON, sclpcon_parse) < 0)
+        exit(1);
     if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0)
         exit(1);
 
-- 
1.7.10.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]