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