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 "chardev-internal.h"
33 /* MUX driver for serial I/O splitting */
36 * Set to false by suspend_mux_open. Open events are delayed until
37 * resume_mux_open. Usually suspend_mux_open is called before
38 * command line processing and resume_mux_open afterwards.
40 static bool muxes_opened
= true;
42 /* Called with chr_write_lock held. */
43 static int mux_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
45 MuxChardev
*d
= MUX_CHARDEV(chr
);
48 ret
= qemu_chr_fe_write(&d
->chr
, buf
, len
);
53 for (i
= 0; i
< len
; i
++) {
59 ti
= qemu_clock_get_ms(QEMU_CLOCK_REALTIME
);
60 if (d
->timestamps_start
== -1) {
61 d
->timestamps_start
= ti
;
63 ti
-= d
->timestamps_start
;
65 snprintf(buf1
, sizeof(buf1
),
66 "[%02d:%02d:%02d.%03d] ",
71 /* XXX this blocks entire thread. Rewrite to use
72 * qemu_chr_fe_write and background I/O callbacks */
73 qemu_chr_fe_write_all(&d
->chr
,
74 (uint8_t *)buf1
, strlen(buf1
));
77 ret
+= qemu_chr_fe_write(&d
->chr
, buf
+ i
, 1);
86 static const char * const mux_help
[] = {
87 "% h print this help\n\r",
88 "% x exit emulator\n\r",
89 "% s save disk data back to file (if -snapshot)\n\r",
90 "% t toggle console timestamps\n\r",
91 "% b send break (magic sysrq)\n\r",
92 "% c switch between console and monitor\n\r",
97 int term_escape_char
= 0x01; /* ctrl-a is used for escape */
98 static void mux_print_help(Chardev
*chr
)
101 char ebuf
[15] = "Escape-Char";
102 char cbuf
[50] = "\n\r";
104 if (term_escape_char
> 0 && term_escape_char
< 26) {
105 snprintf(cbuf
, sizeof(cbuf
), "\n\r");
106 snprintf(ebuf
, sizeof(ebuf
), "C-%c", term_escape_char
- 1 + 'a');
108 snprintf(cbuf
, sizeof(cbuf
),
109 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
112 /* XXX this blocks entire thread. Rewrite to use
113 * qemu_chr_fe_write and background I/O callbacks */
114 qemu_chr_write_all(chr
, (uint8_t *)cbuf
, strlen(cbuf
));
115 for (i
= 0; mux_help
[i
] != NULL
; i
++) {
116 for (j
= 0; mux_help
[i
][j
] != '\0'; j
++) {
117 if (mux_help
[i
][j
] == '%') {
118 qemu_chr_write_all(chr
, (uint8_t *)ebuf
, strlen(ebuf
));
120 qemu_chr_write_all(chr
, (uint8_t *)&mux_help
[i
][j
], 1);
126 static void mux_chr_send_event(MuxChardev
*d
, int mux_nr
, QEMUChrEvent event
)
128 CharBackend
*be
= d
->backends
[mux_nr
];
130 if (be
&& be
->chr_event
) {
131 be
->chr_event(be
->opaque
, event
);
135 static void mux_chr_be_event(Chardev
*chr
, QEMUChrEvent event
)
137 MuxChardev
*d
= MUX_CHARDEV(chr
);
139 if (d
->focus
!= -1) {
140 mux_chr_send_event(d
, d
->focus
, event
);
144 static int mux_proc_byte(Chardev
*chr
, MuxChardev
*d
, int ch
)
146 if (d
->term_got_escape
) {
147 d
->term_got_escape
= 0;
148 if (ch
== term_escape_char
) {
158 const char *term
= "QEMU: Terminated\n\r";
159 qemu_chr_write_all(chr
, (uint8_t *)term
, strlen(term
));
167 qemu_chr_be_event(chr
, CHR_EVENT_BREAK
);
170 assert(d
->mux_cnt
> 0); /* handler registered with first fe */
171 /* Switch to the next registered device */
172 mux_set_focus(chr
, (d
->focus
+ 1) % d
->mux_cnt
);
175 d
->timestamps
= !d
->timestamps
;
176 d
->timestamps_start
= -1;
180 } else if (ch
== term_escape_char
) {
181 d
->term_got_escape
= 1;
189 static void mux_chr_accept_input(Chardev
*chr
)
191 MuxChardev
*d
= MUX_CHARDEV(chr
);
193 CharBackend
*be
= d
->backends
[m
];
195 while (be
&& d
->prod
[m
] != d
->cons
[m
] &&
196 be
->chr_can_read
&& be
->chr_can_read(be
->opaque
)) {
197 be
->chr_read(be
->opaque
,
198 &d
->buffer
[m
][d
->cons
[m
]++ & MUX_BUFFER_MASK
], 1);
202 static int mux_chr_can_read(void *opaque
)
204 MuxChardev
*d
= MUX_CHARDEV(opaque
);
206 CharBackend
*be
= d
->backends
[m
];
208 if ((d
->prod
[m
] - d
->cons
[m
]) < MUX_BUFFER_SIZE
) {
212 if (be
&& be
->chr_can_read
) {
213 return be
->chr_can_read(be
->opaque
);
219 static void mux_chr_read(void *opaque
, const uint8_t *buf
, int size
)
221 Chardev
*chr
= CHARDEV(opaque
);
222 MuxChardev
*d
= MUX_CHARDEV(opaque
);
224 CharBackend
*be
= d
->backends
[m
];
227 mux_chr_accept_input(opaque
);
229 for (i
= 0; i
< size
; i
++)
230 if (mux_proc_byte(chr
, d
, buf
[i
])) {
231 if (d
->prod
[m
] == d
->cons
[m
] &&
232 be
&& be
->chr_can_read
&&
233 be
->chr_can_read(be
->opaque
)) {
234 be
->chr_read(be
->opaque
, &buf
[i
], 1);
236 d
->buffer
[m
][d
->prod
[m
]++ & MUX_BUFFER_MASK
] = buf
[i
];
241 void mux_chr_send_all_event(Chardev
*chr
, QEMUChrEvent event
)
243 MuxChardev
*d
= MUX_CHARDEV(chr
);
250 /* Send the event to all registered listeners */
251 for (i
= 0; i
< d
->mux_cnt
; i
++) {
252 mux_chr_send_event(d
, i
, event
);
256 static void mux_chr_event(void *opaque
, QEMUChrEvent event
)
258 mux_chr_send_all_event(CHARDEV(opaque
), event
);
261 static GSource
*mux_chr_add_watch(Chardev
*s
, GIOCondition cond
)
263 MuxChardev
*d
= MUX_CHARDEV(s
);
264 Chardev
*chr
= qemu_chr_fe_get_driver(&d
->chr
);
265 ChardevClass
*cc
= CHARDEV_GET_CLASS(chr
);
267 if (!cc
->chr_add_watch
) {
271 return cc
->chr_add_watch(chr
, cond
);
274 static void char_mux_finalize(Object
*obj
)
276 MuxChardev
*d
= MUX_CHARDEV(obj
);
279 for (i
= 0; i
< d
->mux_cnt
; i
++) {
280 CharBackend
*be
= d
->backends
[i
];
285 qemu_chr_fe_deinit(&d
->chr
, false);
288 static void mux_chr_update_read_handlers(Chardev
*chr
)
290 MuxChardev
*d
= MUX_CHARDEV(chr
);
292 /* Fix up the real driver with mux routines */
293 qemu_chr_fe_set_handlers_full(&d
->chr
,
299 chr
->gcontext
, true, false);
302 void mux_set_focus(Chardev
*chr
, int focus
)
304 MuxChardev
*d
= MUX_CHARDEV(chr
);
307 assert(focus
< d
->mux_cnt
);
309 if (d
->focus
!= -1) {
310 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_OUT
);
314 chr
->be
= d
->backends
[focus
];
315 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_IN
);
318 static void qemu_chr_open_mux(Chardev
*chr
,
319 ChardevBackend
*backend
,
323 ChardevMux
*mux
= backend
->u
.mux
.data
;
325 MuxChardev
*d
= MUX_CHARDEV(chr
);
327 drv
= qemu_chr_find(mux
->chardev
);
329 error_setg(errp
, "mux: base chardev %s not found", mux
->chardev
);
334 /* only default to opened state if we've realized the initial
337 *be_opened
= muxes_opened
;
338 qemu_chr_fe_init(&d
->chr
, drv
, errp
);
341 static void qemu_chr_parse_mux(QemuOpts
*opts
, ChardevBackend
*backend
,
344 const char *chardev
= qemu_opt_get(opts
, "chardev");
347 if (chardev
== NULL
) {
348 error_setg(errp
, "chardev: mux: no chardev given");
351 backend
->type
= CHARDEV_BACKEND_KIND_MUX
;
352 mux
= backend
->u
.mux
.data
= g_new0(ChardevMux
, 1);
353 qemu_chr_parse_common(opts
, qapi_ChardevMux_base(mux
));
354 mux
->chardev
= g_strdup(chardev
);
358 * Called after processing of default and command-line-specified
359 * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
360 * to a mux chardev. This is done here to ensure that
361 * output/prompts/banners are only displayed for the FE that has
362 * focus when initial command-line processing/machine init is
365 * After this point, any new FE attached to any new or existing
366 * mux will receive CHR_EVENT_OPENED notifications for the BE
369 static void open_muxes(Chardev
*chr
)
371 /* send OPENED to all already-attached FEs */
372 mux_chr_send_all_event(chr
, CHR_EVENT_OPENED
);
375 * mark mux as OPENED so any new FEs will immediately receive
381 void suspend_mux_open(void)
383 muxes_opened
= false;
386 static int chardev_options_parsed_cb(Object
*child
, void *opaque
)
388 Chardev
*chr
= (Chardev
*)child
;
389 ChardevClass
*class = CHARDEV_GET_CLASS(chr
);
391 if (!chr
->be_open
&& class->chr_options_parsed
) {
392 class->chr_options_parsed(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_options_parsed
= open_muxes
;
416 cc
->chr_update_read_handler
= mux_chr_update_read_handlers
;
419 static const TypeInfo char_mux_type_info
= {
420 .name
= TYPE_CHARDEV_MUX
,
421 .parent
= TYPE_CHARDEV
,
422 .class_init
= char_mux_class_init
,
423 .instance_size
= sizeof(MuxChardev
),
424 .instance_finalize
= char_mux_finalize
,
427 static void register_types(void)
429 type_register_static(&char_mux_type_info
);
432 type_init(register_types
);