Revision 130c57c0

b/hw/s390x/Makefile.objs
3 3
obj-y := $(addprefix ../,$(obj-y))
4 4
obj-y += sclp.o
5 5
obj-y += event-facility.o
6
obj-y += sclpquiesce.o
6
obj-y += sclpquiesce.o sclpconsole.o
b/hw/s390x/sclpconsole.c
1
/*
2
 * SCLP event type
3
 *    Ascii Console Data (VT220 Console)
4
 *
5
 * Copyright IBM, Corp. 2012
6
 *
7
 * Authors:
8
 *  Heinz Graalfs <graalfs@de.ibm.com>
9
 *
10
 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
11
 * option) any later version.  See the COPYING file in the top-level directory.
12
 *
13
 */
14

  
15
#include <hw/qdev.h>
16
#include "qemu-thread.h"
17

  
18
#include "sclp.h"
19
#include "event-facility.h"
20

  
21
typedef struct ASCIIConsoleData {
22
    EventBufferHeader ebh;
23
    char data[0];
24
} QEMU_PACKED ASCIIConsoleData;
25

  
26
/* max size for ASCII data in 4K SCCB page */
27
#define SIZE_BUFFER_VT220 4080
28

  
29
typedef struct SCLPConsole {
30
    SCLPEvent event;
31
    CharDriverState *chr;
32
    /* io vector                                                       */
33
    uint8_t *iov;           /* iov buffer pointer                      */
34
    uint8_t *iov_sclp;      /* pointer to SCLP read offset             */
35
    uint8_t *iov_bs;        /* pointer byte stream read offset         */
36
    uint32_t iov_data_len;  /* length of byte stream in buffer         */
37
    uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
38
    qemu_irq irq_read_vt220;
39
} SCLPConsole;
40

  
41
/* character layer call-back functions */
42

  
43
/* Return number of bytes that fit into iov buffer */
44
static int chr_can_read(void *opaque)
45
{
46
    int can_read;
47
    SCLPConsole *scon = opaque;
48

  
49
    can_read = SIZE_BUFFER_VT220 - scon->iov_data_len;
50

  
51
    return can_read;
52
}
53

  
54
/* Receive n bytes from character layer, save in iov buffer,
55
 * and set event pending */
56
static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
57
                                   int size)
58
{
59
    assert(scon->iov);
60

  
61
    /* read data must fit into current buffer */
62
    assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
63

  
64
    /* put byte-stream from character layer into buffer */
65
    memcpy(scon->iov_bs, buf, size);
66
    scon->iov_data_len += size;
67
    scon->iov_sclp_rest += size;
68
    scon->iov_bs += size;
69
    scon->event.event_pending = true;
70
}
71

  
72
/* Send data from a char device over to the guest */
73
static void chr_read(void *opaque, const uint8_t *buf, int size)
74
{
75
    SCLPConsole *scon = opaque;
76

  
77
    assert(scon);
78

  
79
    receive_from_chr_layer(scon, buf, size);
80
    /* trigger SCLP read operation */
81
    qemu_irq_raise(scon->irq_read_vt220);
82
}
83

  
84
static void chr_event(void *opaque, int event)
85
{
86
    SCLPConsole *scon = opaque;
87

  
88
    switch (event) {
89
    case CHR_EVENT_OPENED:
90
        if (!scon->iov) {
91
            scon->iov = g_malloc0(SIZE_BUFFER_VT220);
92
            scon->iov_sclp = scon->iov;
93
            scon->iov_bs = scon->iov;
94
            scon->iov_data_len = 0;
95
            scon->iov_sclp_rest = 0;
96
        }
97
        break;
98
    case CHR_EVENT_CLOSED:
99
        if (scon->iov) {
100
            g_free(scon->iov);
101
            scon->iov = NULL;
102
        }
103
        break;
104
    }
105
}
106

  
107
/* functions to be called by event facility */
108

  
109
static int event_type(void)
110
{
111
    return SCLP_EVENT_ASCII_CONSOLE_DATA;
112
}
113

  
114
static unsigned int send_mask(void)
115
{
116
    return SCLP_EVENT_MASK_MSG_ASCII;
117
}
118

  
119
static unsigned int receive_mask(void)
120
{
121
    return SCLP_EVENT_MASK_MSG_ASCII;
122
}
123

  
124
/* triggered by SCLP's read_event_data -
125
 * copy console data byte-stream into provided (SCLP) buffer
126
 */
127
static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
128
                             int avail)
129
{
130
    SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
131

  
132
    /* first byte is hex 0 saying an ascii string follows */
133
    *buf++ = '\0';
134
    avail--;
135
    /* if all data fit into provided SCLP buffer */
136
    if (avail >= cons->iov_sclp_rest) {
137
        /* copy character byte-stream to SCLP buffer */
138
        memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
139
        *size = cons->iov_sclp_rest + 1;
140
        cons->iov_sclp = cons->iov;
141
        cons->iov_bs = cons->iov;
142
        cons->iov_data_len = 0;
143
        cons->iov_sclp_rest = 0;
144
        event->event_pending = false;
145
        /* data provided and no more data pending */
146
    } else {
147
        /* if provided buffer is too small, just copy part */
148
        memcpy(buf, cons->iov_sclp, avail);
149
        *size = avail + 1;
150
        cons->iov_sclp_rest -= avail;
151
        cons->iov_sclp += avail;
152
        /* more data pending */
153
    }
154
}
155

  
156
static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
157
                           int *slen)
158
{
159
    int avail;
160
    size_t src_len;
161
    uint8_t *to;
162
    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
163

  
164
    if (!event->event_pending) {
165
        /* no data pending */
166
        return 0;
167
    }
168

  
169
    to = (uint8_t *)&acd->data;
170
    avail = *slen - sizeof(ASCIIConsoleData);
171
    get_console_data(event, to, &src_len, avail);
172

  
173
    acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
174
    acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
175
    acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
176
    *slen = avail - src_len;
177

  
178
    return 1;
179
}
180

  
181
/* triggered by SCLP's write_event_data
182
 *  - write console data into character layer
183
 *  returns < 0 if an error occured
184
 */
185
static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
186
                                  size_t len)
187
{
188
    ssize_t ret = 0;
189
    const uint8_t *iov_offset;
190
    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
191

  
192
    if (!scon->chr) {
193
        /* If there's no backend, we can just say we consumed all data. */
194
        return len;
195
    }
196

  
197
    iov_offset = buf;
198
    while (len > 0) {
199
        ret = qemu_chr_fe_write(scon->chr, buf, len);
200
        if (ret == 0) {
201
            /* a pty doesn't seem to be connected - no error */
202
            len = 0;
203
        } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
204
            len -= ret;
205
            iov_offset += ret;
206
        } else {
207
            len = 0;
208
        }
209
    }
210

  
211
    return ret;
212
}
213

  
214
static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
215
{
216
    int rc;
217
    int length;
218
    ssize_t written;
219
    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
220

  
221
    length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
222
    written = write_console_data(event, (uint8_t *)acd->data, length);
223

  
224
    rc = SCLP_RC_NORMAL_COMPLETION;
225
    /* set event buffer accepted flag */
226
    evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
227

  
228
    /* written will be zero if a pty is not connected - don't treat as error */
229
    if (written < 0) {
230
        /* event buffer not accepted due to error in character layer */
231
        evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
232
        rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
233
    }
234

  
235
    return rc;
236
}
237

  
238
static void trigger_ascii_console_data(void *env, int n, int level)
239
{
240
    sclp_service_interrupt(0);
241
}
242

  
243
/* qemu object creation and initialization functions */
244

  
245
/* tell character layer our call-back functions */
246
static int console_init(SCLPEvent *event)
247
{
248
    static bool console_available;
249

  
250
    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
251

  
252
    if (console_available) {
253
        error_report("Multiple VT220 operator consoles are not supported");
254
        return -1;
255
    }
256
    console_available = true;
257
    event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
258
    if (scon->chr) {
259
        qemu_chr_add_handlers(scon->chr, chr_can_read,
260
                              chr_read, chr_event, scon);
261
    }
262
    scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
263
                                               NULL, 1);
264

  
265
    return 0;
266
}
267

  
268
static int console_exit(SCLPEvent *event)
269
{
270
    return 0;
271
}
272

  
273
static Property console_properties[] = {
274
    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
275
    DEFINE_PROP_END_OF_LIST(),
276
};
277

  
278
static void console_class_init(ObjectClass *klass, void *data)
279
{
280
    DeviceClass *dc = DEVICE_CLASS(klass);
281
    SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
282

  
283
    dc->props = console_properties;
284
    ec->init = console_init;
285
    ec->exit = console_exit;
286
    ec->get_send_mask = send_mask;
287
    ec->get_receive_mask = receive_mask;
288
    ec->event_type = event_type;
289
    ec->read_event_data = read_event_data;
290
    ec->write_event_data = write_event_data;
291
}
292

  
293
static TypeInfo sclp_console_info = {
294
    .name          = "sclpconsole",
295
    .parent        = TYPE_SCLP_EVENT,
296
    .instance_size = sizeof(SCLPConsole),
297
    .class_init    = console_class_init,
298
    .class_size    = sizeof(SCLPEventClass),
299
};
300

  
301
static void register_types(void)
302
{
303
    type_register_static(&sclp_console_info);
304
}
305

  
306
type_init(register_types)

Also available in: Unified diff