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/option.h"
28 #include "chardev/char.h"
29 #include "sysemu/block-backend.h"
30 #include "sysemu/sysemu.h"
31 #include "chardev/char-mux.h"
33 /* MUX driver for serial I/O splitting */
35 /* Called with chr_write_lock held. */
36 static int mux_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
38 MuxChardev
*d
= MUX_CHARDEV(chr
);
41 ret
= qemu_chr_fe_write(&d
->chr
, buf
, len
);
46 for (i
= 0; i
< len
; i
++) {
52 ti
= qemu_clock_get_ms(QEMU_CLOCK_REALTIME
);
53 if (d
->timestamps_start
== -1) {
54 d
->timestamps_start
= ti
;
56 ti
-= d
->timestamps_start
;
58 snprintf(buf1
, sizeof(buf1
),
59 "[%02d:%02d:%02d.%03d] ",
64 /* XXX this blocks entire thread. Rewrite to use
65 * qemu_chr_fe_write and background I/O callbacks */
66 qemu_chr_fe_write_all(&d
->chr
,
67 (uint8_t *)buf1
, strlen(buf1
));
70 ret
+= qemu_chr_fe_write(&d
->chr
, buf
+ i
, 1);
79 static const char * const mux_help
[] = {
80 "% h print this help\n\r",
81 "% x exit emulator\n\r",
82 "% s save disk data back to file (if -snapshot)\n\r",
83 "% t toggle console timestamps\n\r",
84 "% b send break (magic sysrq)\n\r",
85 "% c switch between console and monitor\n\r",
90 int term_escape_char
= 0x01; /* ctrl-a is used for escape */
91 static void mux_print_help(Chardev
*chr
)
94 char ebuf
[15] = "Escape-Char";
95 char cbuf
[50] = "\n\r";
97 if (term_escape_char
> 0 && term_escape_char
< 26) {
98 snprintf(cbuf
, sizeof(cbuf
), "\n\r");
99 snprintf(ebuf
, sizeof(ebuf
), "C-%c", term_escape_char
- 1 + 'a');
101 snprintf(cbuf
, sizeof(cbuf
),
102 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
105 /* XXX this blocks entire thread. Rewrite to use
106 * qemu_chr_fe_write and background I/O callbacks */
107 qemu_chr_write_all(chr
, (uint8_t *)cbuf
, strlen(cbuf
));
108 for (i
= 0; mux_help
[i
] != NULL
; i
++) {
109 for (j
= 0; mux_help
[i
][j
] != '\0'; j
++) {
110 if (mux_help
[i
][j
] == '%') {
111 qemu_chr_write_all(chr
, (uint8_t *)ebuf
, strlen(ebuf
));
113 qemu_chr_write_all(chr
, (uint8_t *)&mux_help
[i
][j
], 1);
119 static void mux_chr_send_event(MuxChardev
*d
, int mux_nr
, int event
)
121 CharBackend
*be
= d
->backends
[mux_nr
];
123 if (be
&& be
->chr_event
) {
124 be
->chr_event(be
->opaque
, event
);
128 static void mux_chr_be_event(Chardev
*chr
, int event
)
130 MuxChardev
*d
= MUX_CHARDEV(chr
);
132 if (d
->focus
!= -1) {
133 mux_chr_send_event(d
, d
->focus
, event
);
137 static int mux_proc_byte(Chardev
*chr
, MuxChardev
*d
, int ch
)
139 if (d
->term_got_escape
) {
140 d
->term_got_escape
= 0;
141 if (ch
== term_escape_char
) {
151 const char *term
= "QEMU: Terminated\n\r";
152 qemu_chr_write_all(chr
, (uint8_t *)term
, strlen(term
));
160 qemu_chr_be_event(chr
, CHR_EVENT_BREAK
);
163 assert(d
->mux_cnt
> 0); /* handler registered with first fe */
164 /* Switch to the next registered device */
165 mux_set_focus(chr
, (d
->focus
+ 1) % d
->mux_cnt
);
168 d
->timestamps
= !d
->timestamps
;
169 d
->timestamps_start
= -1;
173 } else if (ch
== term_escape_char
) {
174 d
->term_got_escape
= 1;
182 static void mux_chr_accept_input(Chardev
*chr
)
184 MuxChardev
*d
= MUX_CHARDEV(chr
);
186 CharBackend
*be
= d
->backends
[m
];
188 while (be
&& d
->prod
[m
] != d
->cons
[m
] &&
189 be
->chr_can_read
&& be
->chr_can_read(be
->opaque
)) {
190 be
->chr_read(be
->opaque
,
191 &d
->buffer
[m
][d
->cons
[m
]++ & MUX_BUFFER_MASK
], 1);
195 static int mux_chr_can_read(void *opaque
)
197 MuxChardev
*d
= MUX_CHARDEV(opaque
);
199 CharBackend
*be
= d
->backends
[m
];
201 if ((d
->prod
[m
] - d
->cons
[m
]) < MUX_BUFFER_SIZE
) {
205 if (be
&& be
->chr_can_read
) {
206 return be
->chr_can_read(be
->opaque
);
212 static void mux_chr_read(void *opaque
, const uint8_t *buf
, int size
)
214 Chardev
*chr
= CHARDEV(opaque
);
215 MuxChardev
*d
= MUX_CHARDEV(opaque
);
217 CharBackend
*be
= d
->backends
[m
];
220 mux_chr_accept_input(opaque
);
222 for (i
= 0; i
< size
; i
++)
223 if (mux_proc_byte(chr
, d
, buf
[i
])) {
224 if (d
->prod
[m
] == d
->cons
[m
] &&
225 be
&& be
->chr_can_read
&&
226 be
->chr_can_read(be
->opaque
)) {
227 be
->chr_read(be
->opaque
, &buf
[i
], 1);
229 d
->buffer
[m
][d
->prod
[m
]++ & MUX_BUFFER_MASK
] = buf
[i
];
234 void mux_chr_send_all_event(Chardev
*chr
, int event
)
236 MuxChardev
*d
= MUX_CHARDEV(chr
);
239 if (!machine_init_done
) {
243 /* Send the event to all registered listeners */
244 for (i
= 0; i
< d
->mux_cnt
; i
++) {
245 mux_chr_send_event(d
, i
, event
);
249 static void mux_chr_event(void *opaque
, int event
)
251 mux_chr_send_all_event(CHARDEV(opaque
), event
);
254 static GSource
*mux_chr_add_watch(Chardev
*s
, GIOCondition cond
)
256 MuxChardev
*d
= MUX_CHARDEV(s
);
257 Chardev
*chr
= qemu_chr_fe_get_driver(&d
->chr
);
258 ChardevClass
*cc
= CHARDEV_GET_CLASS(chr
);
260 if (!cc
->chr_add_watch
) {
264 return cc
->chr_add_watch(chr
, cond
);
267 static void char_mux_finalize(Object
*obj
)
269 MuxChardev
*d
= MUX_CHARDEV(obj
);
272 for (i
= 0; i
< d
->mux_cnt
; i
++) {
273 CharBackend
*be
= d
->backends
[i
];
278 qemu_chr_fe_deinit(&d
->chr
, false);
281 static void mux_chr_update_read_handlers(Chardev
*chr
)
283 MuxChardev
*d
= MUX_CHARDEV(chr
);
285 /* Fix up the real driver with mux routines */
286 qemu_chr_fe_set_handlers_full(&d
->chr
,
292 chr
->gcontext
, true, false);
295 void mux_set_focus(Chardev
*chr
, int focus
)
297 MuxChardev
*d
= MUX_CHARDEV(chr
);
300 assert(focus
< d
->mux_cnt
);
302 if (d
->focus
!= -1) {
303 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_OUT
);
307 chr
->be
= d
->backends
[focus
];
308 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_IN
);
311 static void qemu_chr_open_mux(Chardev
*chr
,
312 ChardevBackend
*backend
,
316 ChardevMux
*mux
= backend
->u
.mux
.data
;
318 MuxChardev
*d
= MUX_CHARDEV(chr
);
320 drv
= qemu_chr_find(mux
->chardev
);
322 error_setg(errp
, "mux: base chardev %s not found", mux
->chardev
);
327 /* only default to opened state if we've realized the initial
330 *be_opened
= machine_init_done
;
331 qemu_chr_fe_init(&d
->chr
, drv
, errp
);
334 static void qemu_chr_parse_mux(QemuOpts
*opts
, ChardevBackend
*backend
,
337 const char *chardev
= qemu_opt_get(opts
, "chardev");
340 if (chardev
== NULL
) {
341 error_setg(errp
, "chardev: mux: no chardev given");
344 backend
->type
= CHARDEV_BACKEND_KIND_MUX
;
345 mux
= backend
->u
.mux
.data
= g_new0(ChardevMux
, 1);
346 qemu_chr_parse_common(opts
, qapi_ChardevMux_base(mux
));
347 mux
->chardev
= g_strdup(chardev
);
351 * Called after processing of default and command-line-specified
352 * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
353 * to a mux chardev. This is done here to ensure that
354 * output/prompts/banners are only displayed for the FE that has
355 * focus when initial command-line processing/machine init is
358 * After this point, any new FE attached to any new or existing
359 * mux will receive CHR_EVENT_OPENED notifications for the BE
362 static int open_muxes(Chardev
*chr
)
364 /* send OPENED to all already-attached FEs */
365 mux_chr_send_all_event(chr
, CHR_EVENT_OPENED
);
367 * mark mux as OPENED so any new FEs will immediately receive
375 static void char_mux_class_init(ObjectClass
*oc
, void *data
)
377 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
379 cc
->parse
= qemu_chr_parse_mux
;
380 cc
->open
= qemu_chr_open_mux
;
381 cc
->chr_write
= mux_chr_write
;
382 cc
->chr_accept_input
= mux_chr_accept_input
;
383 cc
->chr_add_watch
= mux_chr_add_watch
;
384 cc
->chr_be_event
= mux_chr_be_event
;
385 cc
->chr_machine_done
= open_muxes
;
386 cc
->chr_update_read_handler
= mux_chr_update_read_handlers
;
389 static const TypeInfo char_mux_type_info
= {
390 .name
= TYPE_CHARDEV_MUX
,
391 .parent
= TYPE_CHARDEV
,
392 .class_init
= char_mux_class_init
,
393 .instance_size
= sizeof(MuxChardev
),
394 .instance_finalize
= char_mux_finalize
,
397 static void register_types(void)
399 type_register_static(&char_mux_type_info
);
402 type_init(register_types
);