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 "qapi/qapi-commands-control.h"
32 #include "chardev-internal.h"
34 /* MUX driver for serial I/O splitting */
37 * Set to false by suspend_mux_open. Open events are delayed until
38 * resume_mux_open. Usually suspend_mux_open is called before
39 * command line processing and resume_mux_open afterwards.
41 static bool muxes_opened
= true;
43 /* Called with chr_write_lock held. */
44 static int mux_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
46 MuxChardev
*d
= MUX_CHARDEV(chr
);
49 ret
= qemu_chr_fe_write(&d
->chr
, buf
, len
);
54 for (i
= 0; i
< len
; i
++) {
60 ti
= qemu_clock_get_ms(QEMU_CLOCK_REALTIME
);
61 if (d
->timestamps_start
== -1) {
62 d
->timestamps_start
= ti
;
64 ti
-= d
->timestamps_start
;
66 snprintf(buf1
, sizeof(buf1
),
67 "[%02d:%02d:%02d.%03d] ",
72 /* XXX this blocks entire thread. Rewrite to use
73 * qemu_chr_fe_write and background I/O callbacks */
74 qemu_chr_fe_write_all(&d
->chr
,
75 (uint8_t *)buf1
, strlen(buf1
));
78 ret
+= qemu_chr_fe_write(&d
->chr
, buf
+ i
, 1);
87 static const char * const mux_help
[] = {
88 "% h print this help\n\r",
89 "% x exit emulator\n\r",
90 "% s save disk data back to file (if -snapshot)\n\r",
91 "% t toggle console timestamps\n\r",
92 "% b send break (magic sysrq)\n\r",
93 "% c switch between console and monitor\n\r",
98 int term_escape_char
= 0x01; /* ctrl-a is used for escape */
99 static void mux_print_help(Chardev
*chr
)
102 char ebuf
[15] = "Escape-Char";
103 char cbuf
[50] = "\n\r";
105 if (term_escape_char
> 0 && term_escape_char
< 26) {
106 snprintf(cbuf
, sizeof(cbuf
), "\n\r");
107 snprintf(ebuf
, sizeof(ebuf
), "C-%c", term_escape_char
- 1 + 'a');
109 snprintf(cbuf
, sizeof(cbuf
),
110 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
113 /* XXX this blocks entire thread. Rewrite to use
114 * qemu_chr_fe_write and background I/O callbacks */
115 qemu_chr_write_all(chr
, (uint8_t *)cbuf
, strlen(cbuf
));
116 for (i
= 0; mux_help
[i
] != NULL
; i
++) {
117 for (j
= 0; mux_help
[i
][j
] != '\0'; j
++) {
118 if (mux_help
[i
][j
] == '%') {
119 qemu_chr_write_all(chr
, (uint8_t *)ebuf
, strlen(ebuf
));
121 qemu_chr_write_all(chr
, (uint8_t *)&mux_help
[i
][j
], 1);
127 static void mux_chr_send_event(MuxChardev
*d
, int mux_nr
, QEMUChrEvent event
)
129 CharBackend
*be
= d
->backends
[mux_nr
];
131 if (be
&& be
->chr_event
) {
132 be
->chr_event(be
->opaque
, event
);
136 static void mux_chr_be_event(Chardev
*chr
, QEMUChrEvent event
)
138 MuxChardev
*d
= MUX_CHARDEV(chr
);
140 if (d
->focus
!= -1) {
141 mux_chr_send_event(d
, d
->focus
, event
);
145 static int mux_proc_byte(Chardev
*chr
, MuxChardev
*d
, int ch
)
147 if (d
->term_got_escape
) {
148 d
->term_got_escape
= 0;
149 if (ch
== term_escape_char
) {
159 const char *term
= "QEMU: Terminated\n\r";
160 qemu_chr_write_all(chr
, (uint8_t *)term
, strlen(term
));
168 qemu_chr_be_event(chr
, CHR_EVENT_BREAK
);
171 assert(d
->mux_cnt
> 0); /* handler registered with first fe */
172 /* Switch to the next registered device */
173 mux_set_focus(chr
, (d
->focus
+ 1) % d
->mux_cnt
);
176 d
->timestamps
= !d
->timestamps
;
177 d
->timestamps_start
= -1;
181 } else if (ch
== term_escape_char
) {
182 d
->term_got_escape
= 1;
190 static void mux_chr_accept_input(Chardev
*chr
)
192 MuxChardev
*d
= MUX_CHARDEV(chr
);
194 CharBackend
*be
= d
->backends
[m
];
196 while (be
&& d
->prod
[m
] != d
->cons
[m
] &&
197 be
->chr_can_read
&& be
->chr_can_read(be
->opaque
)) {
198 be
->chr_read(be
->opaque
,
199 &d
->buffer
[m
][d
->cons
[m
]++ & MUX_BUFFER_MASK
], 1);
203 static int mux_chr_can_read(void *opaque
)
205 MuxChardev
*d
= MUX_CHARDEV(opaque
);
207 CharBackend
*be
= d
->backends
[m
];
209 if ((d
->prod
[m
] - d
->cons
[m
]) < MUX_BUFFER_SIZE
) {
213 if (be
&& be
->chr_can_read
) {
214 return be
->chr_can_read(be
->opaque
);
220 static void mux_chr_read(void *opaque
, const uint8_t *buf
, int size
)
222 Chardev
*chr
= CHARDEV(opaque
);
223 MuxChardev
*d
= MUX_CHARDEV(opaque
);
225 CharBackend
*be
= d
->backends
[m
];
228 mux_chr_accept_input(opaque
);
230 for (i
= 0; i
< size
; i
++)
231 if (mux_proc_byte(chr
, d
, buf
[i
])) {
232 if (d
->prod
[m
] == d
->cons
[m
] &&
233 be
&& be
->chr_can_read
&&
234 be
->chr_can_read(be
->opaque
)) {
235 be
->chr_read(be
->opaque
, &buf
[i
], 1);
237 d
->buffer
[m
][d
->prod
[m
]++ & MUX_BUFFER_MASK
] = buf
[i
];
242 void mux_chr_send_all_event(Chardev
*chr
, QEMUChrEvent event
)
244 MuxChardev
*d
= MUX_CHARDEV(chr
);
251 /* Send the event to all registered listeners */
252 for (i
= 0; i
< d
->mux_cnt
; i
++) {
253 mux_chr_send_event(d
, i
, event
);
257 static void mux_chr_event(void *opaque
, QEMUChrEvent event
)
259 mux_chr_send_all_event(CHARDEV(opaque
), event
);
262 static GSource
*mux_chr_add_watch(Chardev
*s
, GIOCondition cond
)
264 MuxChardev
*d
= MUX_CHARDEV(s
);
265 Chardev
*chr
= qemu_chr_fe_get_driver(&d
->chr
);
266 ChardevClass
*cc
= CHARDEV_GET_CLASS(chr
);
268 if (!cc
->chr_add_watch
) {
272 return cc
->chr_add_watch(chr
, cond
);
275 static void char_mux_finalize(Object
*obj
)
277 MuxChardev
*d
= MUX_CHARDEV(obj
);
280 for (i
= 0; i
< d
->mux_cnt
; i
++) {
281 CharBackend
*be
= d
->backends
[i
];
286 qemu_chr_fe_deinit(&d
->chr
, false);
289 static void mux_chr_update_read_handlers(Chardev
*chr
)
291 MuxChardev
*d
= MUX_CHARDEV(chr
);
293 /* Fix up the real driver with mux routines */
294 qemu_chr_fe_set_handlers_full(&d
->chr
,
300 chr
->gcontext
, true, false);
303 void mux_set_focus(Chardev
*chr
, int focus
)
305 MuxChardev
*d
= MUX_CHARDEV(chr
);
308 assert(focus
< d
->mux_cnt
);
310 if (d
->focus
!= -1) {
311 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_OUT
);
315 chr
->be
= d
->backends
[focus
];
316 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_IN
);
319 static void qemu_chr_open_mux(Chardev
*chr
,
320 ChardevBackend
*backend
,
324 ChardevMux
*mux
= backend
->u
.mux
.data
;
326 MuxChardev
*d
= MUX_CHARDEV(chr
);
328 drv
= qemu_chr_find(mux
->chardev
);
330 error_setg(errp
, "mux: base chardev %s not found", mux
->chardev
);
335 /* only default to opened state if we've realized the initial
338 *be_opened
= muxes_opened
;
339 qemu_chr_fe_init(&d
->chr
, drv
, errp
);
342 static void qemu_chr_parse_mux(QemuOpts
*opts
, ChardevBackend
*backend
,
345 const char *chardev
= qemu_opt_get(opts
, "chardev");
348 if (chardev
== NULL
) {
349 error_setg(errp
, "chardev: mux: no chardev given");
352 backend
->type
= CHARDEV_BACKEND_KIND_MUX
;
353 mux
= backend
->u
.mux
.data
= g_new0(ChardevMux
, 1);
354 qemu_chr_parse_common(opts
, qapi_ChardevMux_base(mux
));
355 mux
->chardev
= g_strdup(chardev
);
359 * Called after processing of default and command-line-specified
360 * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
361 * to a mux chardev. This is done here to ensure that
362 * output/prompts/banners are only displayed for the FE that has
363 * focus when initial command-line processing/machine init is
366 * After this point, any new FE attached to any new or existing
367 * mux will receive CHR_EVENT_OPENED notifications for the BE
370 static void open_muxes(Chardev
*chr
)
372 /* send OPENED to all already-attached FEs */
373 mux_chr_send_all_event(chr
, CHR_EVENT_OPENED
);
376 * mark mux as OPENED so any new FEs will immediately receive
382 void suspend_mux_open(void)
384 muxes_opened
= false;
387 static int chardev_options_parsed_cb(Object
*child
, void *opaque
)
389 Chardev
*chr
= (Chardev
*)child
;
391 if (!chr
->be_open
&& CHARDEV_IS_MUX(chr
)) {
398 void resume_mux_open(void)
401 object_child_foreach(get_chardevs_root(),
402 chardev_options_parsed_cb
, NULL
);
405 static void char_mux_class_init(ObjectClass
*oc
, void *data
)
407 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
409 cc
->parse
= qemu_chr_parse_mux
;
410 cc
->open
= qemu_chr_open_mux
;
411 cc
->chr_write
= mux_chr_write
;
412 cc
->chr_accept_input
= mux_chr_accept_input
;
413 cc
->chr_add_watch
= mux_chr_add_watch
;
414 cc
->chr_be_event
= mux_chr_be_event
;
415 cc
->chr_update_read_handler
= mux_chr_update_read_handlers
;
418 static const TypeInfo char_mux_type_info
= {
419 .name
= TYPE_CHARDEV_MUX
,
420 .parent
= TYPE_CHARDEV
,
421 .class_init
= char_mux_class_init
,
422 .instance_size
= sizeof(MuxChardev
),
423 .instance_finalize
= char_mux_finalize
,
426 static void register_types(void)
428 type_register_static(&char_mux_type_info
);
431 type_init(register_types
);