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
24 #include "qemu/osdep.h"
25 #include "qapi/error.h"
26 #include "qemu-common.h"
27 #include "chardev/char.h"
28 #include "sysemu/block-backend.h"
29 #include "chardev/char-mux.h"
31 /* MUX driver for serial I/O splitting */
33 /* Called with chr_write_lock held. */
34 static int mux_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
36 MuxChardev
*d
= MUX_CHARDEV(chr
);
39 ret
= qemu_chr_fe_write(&d
->chr
, buf
, len
);
44 for (i
= 0; i
< len
; i
++) {
50 ti
= qemu_clock_get_ms(QEMU_CLOCK_REALTIME
);
51 if (d
->timestamps_start
== -1) {
52 d
->timestamps_start
= ti
;
54 ti
-= d
->timestamps_start
;
56 snprintf(buf1
, sizeof(buf1
),
57 "[%02d:%02d:%02d.%03d] ",
62 /* XXX this blocks entire thread. Rewrite to use
63 * qemu_chr_fe_write and background I/O callbacks */
64 qemu_chr_fe_write_all(&d
->chr
,
65 (uint8_t *)buf1
, strlen(buf1
));
68 ret
+= qemu_chr_fe_write(&d
->chr
, buf
+ i
, 1);
77 static const char * const mux_help
[] = {
78 "% h print this help\n\r",
79 "% x exit emulator\n\r",
80 "% s save disk data back to file (if -snapshot)\n\r",
81 "% t toggle console timestamps\n\r",
82 "% b send break (magic sysrq)\n\r",
83 "% c switch between console and monitor\n\r",
88 int term_escape_char
= 0x01; /* ctrl-a is used for escape */
89 static void mux_print_help(Chardev
*chr
)
92 char ebuf
[15] = "Escape-Char";
93 char cbuf
[50] = "\n\r";
95 if (term_escape_char
> 0 && term_escape_char
< 26) {
96 snprintf(cbuf
, sizeof(cbuf
), "\n\r");
97 snprintf(ebuf
, sizeof(ebuf
), "C-%c", term_escape_char
- 1 + 'a');
99 snprintf(cbuf
, sizeof(cbuf
),
100 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
103 /* XXX this blocks entire thread. Rewrite to use
104 * qemu_chr_fe_write and background I/O callbacks */
105 qemu_chr_write_all(chr
, (uint8_t *)cbuf
, strlen(cbuf
));
106 for (i
= 0; mux_help
[i
] != NULL
; i
++) {
107 for (j
= 0; mux_help
[i
][j
] != '\0'; j
++) {
108 if (mux_help
[i
][j
] == '%') {
109 qemu_chr_write_all(chr
, (uint8_t *)ebuf
, strlen(ebuf
));
111 qemu_chr_write_all(chr
, (uint8_t *)&mux_help
[i
][j
], 1);
117 static void mux_chr_send_event(MuxChardev
*d
, int mux_nr
, int event
)
119 CharBackend
*be
= d
->backends
[mux_nr
];
121 if (be
&& be
->chr_event
) {
122 be
->chr_event(be
->opaque
, event
);
126 static void mux_chr_be_event(Chardev
*chr
, int event
)
128 MuxChardev
*d
= MUX_CHARDEV(chr
);
130 if (d
->focus
!= -1) {
131 mux_chr_send_event(d
, d
->focus
, event
);
135 static int mux_proc_byte(Chardev
*chr
, MuxChardev
*d
, int ch
)
137 if (d
->term_got_escape
) {
138 d
->term_got_escape
= 0;
139 if (ch
== term_escape_char
) {
149 const char *term
= "QEMU: Terminated\n\r";
150 qemu_chr_write_all(chr
, (uint8_t *)term
, strlen(term
));
158 qemu_chr_be_event(chr
, CHR_EVENT_BREAK
);
161 assert(d
->mux_cnt
> 0); /* handler registered with first fe */
162 /* Switch to the next registered device */
163 mux_set_focus(chr
, (d
->focus
+ 1) % d
->mux_cnt
);
166 d
->timestamps
= !d
->timestamps
;
167 d
->timestamps_start
= -1;
171 } else if (ch
== term_escape_char
) {
172 d
->term_got_escape
= 1;
180 static void mux_chr_accept_input(Chardev
*chr
)
182 MuxChardev
*d
= MUX_CHARDEV(chr
);
184 CharBackend
*be
= d
->backends
[m
];
186 while (be
&& d
->prod
[m
] != d
->cons
[m
] &&
187 be
->chr_can_read
&& be
->chr_can_read(be
->opaque
)) {
188 be
->chr_read(be
->opaque
,
189 &d
->buffer
[m
][d
->cons
[m
]++ & MUX_BUFFER_MASK
], 1);
193 static int mux_chr_can_read(void *opaque
)
195 MuxChardev
*d
= MUX_CHARDEV(opaque
);
197 CharBackend
*be
= d
->backends
[m
];
199 if ((d
->prod
[m
] - d
->cons
[m
]) < MUX_BUFFER_SIZE
) {
203 if (be
&& be
->chr_can_read
) {
204 return be
->chr_can_read(be
->opaque
);
210 static void mux_chr_read(void *opaque
, const uint8_t *buf
, int size
)
212 Chardev
*chr
= CHARDEV(opaque
);
213 MuxChardev
*d
= MUX_CHARDEV(opaque
);
215 CharBackend
*be
= d
->backends
[m
];
218 mux_chr_accept_input(opaque
);
220 for (i
= 0; i
< size
; i
++)
221 if (mux_proc_byte(chr
, d
, buf
[i
])) {
222 if (d
->prod
[m
] == d
->cons
[m
] &&
223 be
&& be
->chr_can_read
&&
224 be
->chr_can_read(be
->opaque
)) {
225 be
->chr_read(be
->opaque
, &buf
[i
], 1);
227 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 (!muxes_realized
) {
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 void mux_chr_set_handlers(Chardev
*chr
, GMainContext
*context
)
283 MuxChardev
*d
= MUX_CHARDEV(chr
);
285 /* Fix up the real driver with mux routines */
286 qemu_chr_fe_set_handlers(&d
->chr
,
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 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_IN
);
310 static void qemu_chr_open_mux(Chardev
*chr
,
311 ChardevBackend
*backend
,
315 ChardevMux
*mux
= backend
->u
.mux
.data
;
317 MuxChardev
*d
= MUX_CHARDEV(chr
);
319 drv
= qemu_chr_find(mux
->chardev
);
321 error_setg(errp
, "mux: base chardev %s not found", mux
->chardev
);
326 /* only default to opened state if we've realized the initial
329 *be_opened
= muxes_realized
;
330 qemu_chr_fe_init(&d
->chr
, drv
, errp
);
333 static void qemu_chr_parse_mux(QemuOpts
*opts
, ChardevBackend
*backend
,
336 const char *chardev
= qemu_opt_get(opts
, "chardev");
339 if (chardev
== NULL
) {
340 error_setg(errp
, "chardev: mux: no chardev given");
343 backend
->type
= CHARDEV_BACKEND_KIND_MUX
;
344 mux
= backend
->u
.mux
.data
= g_new0(ChardevMux
, 1);
345 qemu_chr_parse_common(opts
, qapi_ChardevMux_base(mux
));
346 mux
->chardev
= g_strdup(chardev
);
349 static void char_mux_class_init(ObjectClass
*oc
, void *data
)
351 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
353 cc
->parse
= qemu_chr_parse_mux
;
354 cc
->open
= qemu_chr_open_mux
;
355 cc
->chr_write
= mux_chr_write
;
356 cc
->chr_accept_input
= mux_chr_accept_input
;
357 cc
->chr_add_watch
= mux_chr_add_watch
;
358 cc
->chr_be_event
= mux_chr_be_event
;
361 static const TypeInfo char_mux_type_info
= {
362 .name
= TYPE_CHARDEV_MUX
,
363 .parent
= TYPE_CHARDEV
,
364 .class_init
= char_mux_class_init
,
365 .instance_size
= sizeof(MuxChardev
),
366 .instance_finalize
= char_mux_finalize
,
369 static void register_types(void)
371 type_register_static(&char_mux_type_info
);
374 type_init(register_types
);