]> Git Repo - qemu.git/blob - hw/s390x/sclpconsole.c
effe51110f38e4b20f5ccbb53a51569ad93f2711
[qemu.git] / 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 <[email protected]>
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 #include "char/char.h"
21
22 typedef struct ASCIIConsoleData {
23     EventBufferHeader ebh;
24     char data[0];
25 } QEMU_PACKED ASCIIConsoleData;
26
27 /* max size for ASCII data in 4K SCCB page */
28 #define SIZE_BUFFER_VT220 4080
29
30 typedef struct SCLPConsole {
31     SCLPEvent event;
32     CharDriverState *chr;
33     /* io vector                                                       */
34     uint8_t *iov;           /* iov buffer pointer                      */
35     uint8_t *iov_sclp;      /* pointer to SCLP read offset             */
36     uint8_t *iov_bs;        /* pointer byte stream read offset         */
37     uint32_t iov_data_len;  /* length of byte stream in buffer         */
38     uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
39     qemu_irq irq_read_vt220;
40 } SCLPConsole;
41
42 /* character layer call-back functions */
43
44 /* Return number of bytes that fit into iov buffer */
45 static int chr_can_read(void *opaque)
46 {
47     SCLPConsole *scon = opaque;
48
49     return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0;
50 }
51
52 /* Receive n bytes from character layer, save in iov buffer,
53  * and set event pending */
54 static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
55                                    int size)
56 {
57     assert(scon->iov);
58
59     /* read data must fit into current buffer */
60     assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
61
62     /* put byte-stream from character layer into buffer */
63     memcpy(scon->iov_bs, buf, size);
64     scon->iov_data_len += size;
65     scon->iov_sclp_rest += size;
66     scon->iov_bs += size;
67     scon->event.event_pending = true;
68 }
69
70 /* Send data from a char device over to the guest */
71 static void chr_read(void *opaque, const uint8_t *buf, int size)
72 {
73     SCLPConsole *scon = opaque;
74
75     assert(scon);
76
77     receive_from_chr_layer(scon, buf, size);
78     /* trigger SCLP read operation */
79     qemu_irq_raise(scon->irq_read_vt220);
80 }
81
82 static void chr_event(void *opaque, int event)
83 {
84     SCLPConsole *scon = opaque;
85
86     switch (event) {
87     case CHR_EVENT_OPENED:
88         if (!scon->iov) {
89             scon->iov = g_malloc0(SIZE_BUFFER_VT220);
90             scon->iov_sclp = scon->iov;
91             scon->iov_bs = scon->iov;
92             scon->iov_data_len = 0;
93             scon->iov_sclp_rest = 0;
94         }
95         break;
96     case CHR_EVENT_CLOSED:
97         if (scon->iov) {
98             g_free(scon->iov);
99             scon->iov = NULL;
100         }
101         break;
102     }
103 }
104
105 /* functions to be called by event facility */
106
107 static int event_type(void)
108 {
109     return SCLP_EVENT_ASCII_CONSOLE_DATA;
110 }
111
112 static unsigned int send_mask(void)
113 {
114     return SCLP_EVENT_MASK_MSG_ASCII;
115 }
116
117 static unsigned int receive_mask(void)
118 {
119     return SCLP_EVENT_MASK_MSG_ASCII;
120 }
121
122 /* triggered by SCLP's read_event_data -
123  * copy console data byte-stream into provided (SCLP) buffer
124  */
125 static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
126                              int avail)
127 {
128     SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
129
130     /* first byte is hex 0 saying an ascii string follows */
131     *buf++ = '\0';
132     avail--;
133     /* if all data fit into provided SCLP buffer */
134     if (avail >= cons->iov_sclp_rest) {
135         /* copy character byte-stream to SCLP buffer */
136         memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
137         *size = cons->iov_sclp_rest + 1;
138         cons->iov_sclp = cons->iov;
139         cons->iov_bs = cons->iov;
140         cons->iov_data_len = 0;
141         cons->iov_sclp_rest = 0;
142         event->event_pending = false;
143         /* data provided and no more data pending */
144     } else {
145         /* if provided buffer is too small, just copy part */
146         memcpy(buf, cons->iov_sclp, avail);
147         *size = avail + 1;
148         cons->iov_sclp_rest -= avail;
149         cons->iov_sclp += avail;
150         /* more data pending */
151     }
152 }
153
154 static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
155                            int *slen)
156 {
157     int avail;
158     size_t src_len;
159     uint8_t *to;
160     ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
161
162     if (!event->event_pending) {
163         /* no data pending */
164         return 0;
165     }
166
167     to = (uint8_t *)&acd->data;
168     avail = *slen - sizeof(ASCIIConsoleData);
169     get_console_data(event, to, &src_len, avail);
170
171     acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
172     acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
173     acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
174     *slen = avail - src_len;
175
176     return 1;
177 }
178
179 /* triggered by SCLP's write_event_data
180  *  - write console data to character layer
181  *  returns < 0 if an error occurred
182  */
183 static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
184                                   size_t len)
185 {
186     ssize_t ret = 0;
187     const uint8_t *iov_offset;
188     SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
189
190     if (!scon->chr) {
191         /* If there's no backend, we can just say we consumed all data. */
192         return len;
193     }
194
195     iov_offset = buf;
196     while (len > 0) {
197         ret = qemu_chr_fe_write(scon->chr, buf, len);
198         if (ret == 0) {
199             /* a pty doesn't seem to be connected - no error */
200             len = 0;
201         } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
202             len -= ret;
203             iov_offset += ret;
204         } else {
205             len = 0;
206         }
207     }
208
209     return ret;
210 }
211
212 static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
213 {
214     int rc;
215     int length;
216     ssize_t written;
217     ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
218
219     length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
220     written = write_console_data(event, (uint8_t *)acd->data, length);
221
222     rc = SCLP_RC_NORMAL_COMPLETION;
223     /* set event buffer accepted flag */
224     evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
225
226     /* written will be zero if a pty is not connected - don't treat as error */
227     if (written < 0) {
228         /* event buffer not accepted due to error in character layer */
229         evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
230         rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
231     }
232
233     return rc;
234 }
235
236 static void trigger_ascii_console_data(void *env, int n, int level)
237 {
238     sclp_service_interrupt(0);
239 }
240
241 /* qemu object creation and initialization functions */
242
243 /* tell character layer our call-back functions */
244 static int console_init(SCLPEvent *event)
245 {
246     static bool console_available;
247
248     SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
249
250     if (console_available) {
251         error_report("Multiple VT220 operator consoles are not supported");
252         return -1;
253     }
254     console_available = true;
255     event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
256     if (scon->chr) {
257         qemu_chr_add_handlers(scon->chr, chr_can_read,
258                               chr_read, chr_event, scon);
259     }
260     scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
261                                                NULL, 1);
262
263     return 0;
264 }
265
266 static int console_exit(SCLPEvent *event)
267 {
268     return 0;
269 }
270
271 static Property console_properties[] = {
272     DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
273     DEFINE_PROP_END_OF_LIST(),
274 };
275
276 static void console_class_init(ObjectClass *klass, void *data)
277 {
278     DeviceClass *dc = DEVICE_CLASS(klass);
279     SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
280
281     dc->props = console_properties;
282     ec->init = console_init;
283     ec->exit = console_exit;
284     ec->get_send_mask = send_mask;
285     ec->get_receive_mask = receive_mask;
286     ec->event_type = event_type;
287     ec->read_event_data = read_event_data;
288     ec->write_event_data = write_event_data;
289 }
290
291 static const TypeInfo sclp_console_info = {
292     .name          = "sclpconsole",
293     .parent        = TYPE_SCLP_EVENT,
294     .instance_size = sizeof(SCLPConsole),
295     .class_init    = console_class_init,
296     .class_size    = sizeof(SCLPEventClass),
297 };
298
299 static void register_types(void)
300 {
301     type_register_static(&sclp_console_info);
302 }
303
304 type_init(register_types)
This page took 0.03191 seconds and 2 git commands to generate.