4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "qemu/osdep.h"
26 #include "qapi/error.h"
27 #include "qemu/module.h"
28 #include "qemu/option.h"
29 #include "chardev/char.h"
30 #include "sysemu/block-backend.h"
31 #include "sysemu/sysemu.h"
32 #include "chardev/char-mux.h"
34 /* MUX driver for serial I/O splitting */
36 /* Called with chr_write_lock held. */
37 static int mux_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
39 MuxChardev
*d
= MUX_CHARDEV(chr
);
42 ret
= qemu_chr_fe_write(&d
->chr
, buf
, len
);
47 for (i
= 0; i
< len
; i
++) {
53 ti
= qemu_clock_get_ms(QEMU_CLOCK_REALTIME
);
54 if (d
->timestamps_start
== -1) {
55 d
->timestamps_start
= ti
;
57 ti
-= d
->timestamps_start
;
59 snprintf(buf1
, sizeof(buf1
),
60 "[%02d:%02d:%02d.%03d] ",
65 /* XXX this blocks entire thread. Rewrite to use
66 * qemu_chr_fe_write and background I/O callbacks */
67 qemu_chr_fe_write_all(&d
->chr
,
68 (uint8_t *)buf1
, strlen(buf1
));
71 ret
+= qemu_chr_fe_write(&d
->chr
, buf
+ i
, 1);
80 static const char * const mux_help
[] = {
81 "% h print this help\n\r",
82 "% x exit emulator\n\r",
83 "% s save disk data back to file (if -snapshot)\n\r",
84 "% t toggle console timestamps\n\r",
85 "% b send break (magic sysrq)\n\r",
86 "% c switch between console and monitor\n\r",
91 int term_escape_char
= 0x01; /* ctrl-a is used for escape */
92 static void mux_print_help(Chardev
*chr
)
95 char ebuf
[15] = "Escape-Char";
96 char cbuf
[50] = "\n\r";
98 if (term_escape_char
> 0 && term_escape_char
< 26) {
99 snprintf(cbuf
, sizeof(cbuf
), "\n\r");
100 snprintf(ebuf
, sizeof(ebuf
), "C-%c", term_escape_char
- 1 + 'a');
102 snprintf(cbuf
, sizeof(cbuf
),
103 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
106 /* XXX this blocks entire thread. Rewrite to use
107 * qemu_chr_fe_write and background I/O callbacks */
108 qemu_chr_write_all(chr
, (uint8_t *)cbuf
, strlen(cbuf
));
109 for (i
= 0; mux_help
[i
] != NULL
; i
++) {
110 for (j
= 0; mux_help
[i
][j
] != '\0'; j
++) {
111 if (mux_help
[i
][j
] == '%') {
112 qemu_chr_write_all(chr
, (uint8_t *)ebuf
, strlen(ebuf
));
114 qemu_chr_write_all(chr
, (uint8_t *)&mux_help
[i
][j
], 1);
120 static void mux_chr_send_event(MuxChardev
*d
, int mux_nr
, QEMUChrEvent event
)
122 CharBackend
*be
= d
->backends
[mux_nr
];
124 if (be
&& be
->chr_event
) {
125 be
->chr_event(be
->opaque
, event
);
129 static void mux_chr_be_event(Chardev
*chr
, QEMUChrEvent event
)
131 MuxChardev
*d
= MUX_CHARDEV(chr
);
133 if (d
->focus
!= -1) {
134 mux_chr_send_event(d
, d
->focus
, event
);
138 static int mux_proc_byte(Chardev
*chr
, MuxChardev
*d
, int ch
)
140 if (d
->term_got_escape
) {
141 d
->term_got_escape
= 0;
142 if (ch
== term_escape_char
) {
152 const char *term
= "QEMU: Terminated\n\r";
153 qemu_chr_write_all(chr
, (uint8_t *)term
, strlen(term
));
161 qemu_chr_be_event(chr
, CHR_EVENT_BREAK
);
164 assert(d
->mux_cnt
> 0); /* handler registered with first fe */
165 /* Switch to the next registered device */
166 mux_set_focus(chr
, (d
->focus
+ 1) % d
->mux_cnt
);
169 d
->timestamps
= !d
->timestamps
;
170 d
->timestamps_start
= -1;
174 } else if (ch
== term_escape_char
) {
175 d
->term_got_escape
= 1;
183 static void mux_chr_accept_input(Chardev
*chr
)
185 MuxChardev
*d
= MUX_CHARDEV(chr
);
187 CharBackend
*be
= d
->backends
[m
];
189 while (be
&& d
->prod
[m
] != d
->cons
[m
] &&
190 be
->chr_can_read
&& be
->chr_can_read(be
->opaque
)) {
191 be
->chr_read(be
->opaque
,
192 &d
->buffer
[m
][d
->cons
[m
]++ & MUX_BUFFER_MASK
], 1);
196 static int mux_chr_can_read(void *opaque
)
198 MuxChardev
*d
= MUX_CHARDEV(opaque
);
200 CharBackend
*be
= d
->backends
[m
];
202 if ((d
->prod
[m
] - d
->cons
[m
]) < MUX_BUFFER_SIZE
) {
206 if (be
&& be
->chr_can_read
) {
207 return be
->chr_can_read(be
->opaque
);
213 static void mux_chr_read(void *opaque
, const uint8_t *buf
, int size
)
215 Chardev
*chr
= CHARDEV(opaque
);
216 MuxChardev
*d
= MUX_CHARDEV(opaque
);
218 CharBackend
*be
= d
->backends
[m
];
221 mux_chr_accept_input(opaque
);
223 for (i
= 0; i
< size
; i
++)
224 if (mux_proc_byte(chr
, d
, buf
[i
])) {
225 if (d
->prod
[m
] == d
->cons
[m
] &&
226 be
&& be
->chr_can_read
&&
227 be
->chr_can_read(be
->opaque
)) {
228 be
->chr_read(be
->opaque
, &buf
[i
], 1);
230 d
->buffer
[m
][d
->prod
[m
]++ & MUX_BUFFER_MASK
] = buf
[i
];
235 void mux_chr_send_all_event(Chardev
*chr
, QEMUChrEvent event
)
237 MuxChardev
*d
= MUX_CHARDEV(chr
);
240 if (!machine_init_done
) {
244 /* Send the event to all registered listeners */
245 for (i
= 0; i
< d
->mux_cnt
; i
++) {
246 mux_chr_send_event(d
, i
, event
);
250 static void mux_chr_event(void *opaque
, QEMUChrEvent event
)
252 mux_chr_send_all_event(CHARDEV(opaque
), event
);
255 static GSource
*mux_chr_add_watch(Chardev
*s
, GIOCondition cond
)
257 MuxChardev
*d
= MUX_CHARDEV(s
);
258 Chardev
*chr
= qemu_chr_fe_get_driver(&d
->chr
);
259 ChardevClass
*cc
= CHARDEV_GET_CLASS(chr
);
261 if (!cc
->chr_add_watch
) {
265 return cc
->chr_add_watch(chr
, cond
);
268 static void char_mux_finalize(Object
*obj
)
270 MuxChardev
*d
= MUX_CHARDEV(obj
);
273 for (i
= 0; i
< d
->mux_cnt
; i
++) {
274 CharBackend
*be
= d
->backends
[i
];
279 qemu_chr_fe_deinit(&d
->chr
, false);
282 static void mux_chr_update_read_handlers(Chardev
*chr
)
284 MuxChardev
*d
= MUX_CHARDEV(chr
);
286 /* Fix up the real driver with mux routines */
287 qemu_chr_fe_set_handlers_full(&d
->chr
,
293 chr
->gcontext
, true, false);
296 void mux_set_focus(Chardev
*chr
, int focus
)
298 MuxChardev
*d
= MUX_CHARDEV(chr
);
301 assert(focus
< d
->mux_cnt
);
303 if (d
->focus
!= -1) {
304 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_OUT
);
308 chr
->be
= d
->backends
[focus
];
309 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_IN
);
312 static void qemu_chr_open_mux(Chardev
*chr
,
313 ChardevBackend
*backend
,
317 ChardevMux
*mux
= backend
->u
.mux
.data
;
319 MuxChardev
*d
= MUX_CHARDEV(chr
);
321 drv
= qemu_chr_find(mux
->chardev
);
323 error_setg(errp
, "mux: base chardev %s not found", mux
->chardev
);
328 /* only default to opened state if we've realized the initial
331 *be_opened
= machine_init_done
;
332 qemu_chr_fe_init(&d
->chr
, drv
, errp
);
335 static void qemu_chr_parse_mux(QemuOpts
*opts
, ChardevBackend
*backend
,
338 const char *chardev
= qemu_opt_get(opts
, "chardev");
341 if (chardev
== NULL
) {
342 error_setg(errp
, "chardev: mux: no chardev given");
345 backend
->type
= CHARDEV_BACKEND_KIND_MUX
;
346 mux
= backend
->u
.mux
.data
= g_new0(ChardevMux
, 1);
347 qemu_chr_parse_common(opts
, qapi_ChardevMux_base(mux
));
348 mux
->chardev
= g_strdup(chardev
);
352 * Called after processing of default and command-line-specified
353 * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
354 * to a mux chardev. This is done here to ensure that
355 * output/prompts/banners are only displayed for the FE that has
356 * focus when initial command-line processing/machine init is
359 * After this point, any new FE attached to any new or existing
360 * mux will receive CHR_EVENT_OPENED notifications for the BE
363 static int open_muxes(Chardev
*chr
)
365 /* send OPENED to all already-attached FEs */
366 mux_chr_send_all_event(chr
, CHR_EVENT_OPENED
);
368 * mark mux as OPENED so any new FEs will immediately receive
376 static void char_mux_class_init(ObjectClass
*oc
, void *data
)
378 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
380 cc
->parse
= qemu_chr_parse_mux
;
381 cc
->open
= qemu_chr_open_mux
;
382 cc
->chr_write
= mux_chr_write
;
383 cc
->chr_accept_input
= mux_chr_accept_input
;
384 cc
->chr_add_watch
= mux_chr_add_watch
;
385 cc
->chr_be_event
= mux_chr_be_event
;
386 cc
->chr_machine_done
= open_muxes
;
387 cc
->chr_update_read_handler
= mux_chr_update_read_handlers
;
390 static const TypeInfo char_mux_type_info
= {
391 .name
= TYPE_CHARDEV_MUX
,
392 .parent
= TYPE_CHARDEV
,
393 .class_init
= char_mux_class_init
,
394 .instance_size
= sizeof(MuxChardev
),
395 .instance_finalize
= char_mux_finalize
,
398 static void register_types(void)
400 type_register_static(&char_mux_type_info
);
403 type_init(register_types
);