15
#include "qemu/osdep.h"
16
#include "qemu/thread.h"
17
#include "qemu/error-report.h"
18
#include "qemu/module.h"
20
#include "hw/s390x/sclp.h"
21
#include "migration/vmstate.h"
22
#include "hw/qdev-properties.h"
23
#include "hw/qdev-properties-system.h"
24
#include "hw/s390x/event-facility.h"
25
#include "chardev/char-fe.h"
26
#include "qom/object.h"
28
typedef struct ASCIIConsoleData {
29
EventBufferHeader ebh;
31
} QEMU_PACKED ASCIIConsoleData;
34
#define SIZE_BUFFER_VT220 4080
39
uint8_t iov[SIZE_BUFFER_VT220];
42
uint32_t iov_data_len;
43
uint32_t iov_sclp_rest;
46
typedef struct SCLPConsole SCLPConsole;
48
#define TYPE_SCLP_CONSOLE "sclpconsole"
49
DECLARE_INSTANCE_CHECKER(SCLPConsole, SCLP_CONSOLE,
55
static int chr_can_read(void *opaque)
57
SCLPConsole *scon = opaque;
58
int avail = SIZE_BUFFER_VT220 - scon->iov_data_len;
67
static void chr_read(void *opaque, const uint8_t *buf, int size)
69
SCLPConsole *scon = opaque;
73
assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
76
memcpy(&scon->iov[scon->iov_bs], buf, size);
77
scon->iov_data_len += size;
78
scon->iov_sclp_rest += size;
80
scon->event.event_pending = true;
81
sclp_service_interrupt(0);
86
static bool can_handle_event(uint8_t type)
88
return type == SCLP_EVENT_ASCII_CONSOLE_DATA;
91
static sccb_mask_t send_mask(void)
93
return SCLP_EVENT_MASK_MSG_ASCII;
96
static sccb_mask_t receive_mask(void)
98
return SCLP_EVENT_MASK_MSG_ASCII;
104
static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
107
SCLPConsole *cons = SCLP_CONSOLE(event);
113
if (avail >= cons->iov_sclp_rest) {
115
memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest);
116
*size = cons->iov_sclp_rest + 1;
119
cons->iov_data_len = 0;
120
cons->iov_sclp_rest = 0;
121
event->event_pending = false;
125
memcpy(buf, &cons->iov[cons->iov_sclp], avail);
127
cons->iov_sclp_rest -= avail;
128
cons->iov_sclp += avail;
132
cons->notify = false;
137
static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
143
ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
145
if (!event->event_pending) {
150
to = (uint8_t *)&acd->data;
151
avail = *slen - sizeof(ASCIIConsoleData);
152
get_console_data(event, to, &src_len, avail);
154
acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
155
acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
156
acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
157
*slen = avail - src_len;
166
static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
169
SCLPConsole *scon = SCLP_CONSOLE(event);
171
if (!qemu_chr_fe_backend_connected(&scon->chr)) {
178
return qemu_chr_fe_write_all(&scon->chr, buf, len);
181
static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
186
ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
188
length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
189
written = write_console_data(event, (uint8_t *)acd->data, length);
191
rc = SCLP_RC_NORMAL_COMPLETION;
193
evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
198
evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
199
rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
205
static const VMStateDescription vmstate_sclpconsole = {
206
.name = "sclpconsole",
208
.minimum_version_id = 0,
209
.fields = (const VMStateField[]) {
210
VMSTATE_BOOL(event.event_pending, SCLPConsole),
211
VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
212
VMSTATE_UINT32(iov_sclp, SCLPConsole),
213
VMSTATE_UINT32(iov_bs, SCLPConsole),
214
VMSTATE_UINT32(iov_data_len, SCLPConsole),
215
VMSTATE_UINT32(iov_sclp_rest, SCLPConsole),
216
VMSTATE_END_OF_LIST()
224
static int console_init(SCLPEvent *event)
226
static bool console_available;
228
SCLPConsole *scon = SCLP_CONSOLE(event);
230
if (console_available) {
231
error_report("Multiple VT220 operator consoles are not supported");
234
console_available = true;
235
qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
236
chr_read, NULL, NULL, scon, NULL, true);
241
static void console_reset(DeviceState *dev)
243
SCLPEvent *event = SCLP_EVENT(dev);
244
SCLPConsole *scon = SCLP_CONSOLE(event);
246
event->event_pending = false;
249
scon->iov_data_len = 0;
250
scon->iov_sclp_rest = 0;
251
scon->notify = false;
254
static Property console_properties[] = {
255
DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
256
DEFINE_PROP_END_OF_LIST(),
259
static void console_class_init(ObjectClass *klass, void *data)
261
DeviceClass *dc = DEVICE_CLASS(klass);
262
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
264
device_class_set_props(dc, console_properties);
265
dc->reset = console_reset;
266
dc->vmsd = &vmstate_sclpconsole;
267
ec->init = console_init;
268
ec->get_send_mask = send_mask;
269
ec->get_receive_mask = receive_mask;
270
ec->can_handle_event = can_handle_event;
271
ec->read_event_data = read_event_data;
272
ec->write_event_data = write_event_data;
273
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
276
static const TypeInfo sclp_console_info = {
277
.name = TYPE_SCLP_CONSOLE,
278
.parent = TYPE_SCLP_EVENT,
279
.instance_size = sizeof(SCLPConsole),
280
.class_init = console_class_init,
281
.class_size = sizeof(SCLPEventClass),
284
static void register_types(void)
286
type_register_static(&sclp_console_info);
289
type_init(register_types)