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 int mux_proc_byte(Chardev
*chr
, MuxChardev
*d
, int ch
)
128 if (d
->term_got_escape
) {
129 d
->term_got_escape
= 0;
130 if (ch
== term_escape_char
) {
140 const char *term
= "QEMU: Terminated\n\r";
141 qemu_chr_write_all(chr
, (uint8_t *)term
, strlen(term
));
149 qemu_chr_be_event(chr
, CHR_EVENT_BREAK
);
152 assert(d
->mux_cnt
> 0); /* handler registered with first fe */
153 /* Switch to the next registered device */
154 mux_set_focus(chr
, (d
->focus
+ 1) % d
->mux_cnt
);
157 d
->timestamps
= !d
->timestamps
;
158 d
->timestamps_start
= -1;
162 } else if (ch
== term_escape_char
) {
163 d
->term_got_escape
= 1;
171 static void mux_chr_accept_input(Chardev
*chr
)
173 MuxChardev
*d
= MUX_CHARDEV(chr
);
175 CharBackend
*be
= d
->backends
[m
];
177 while (be
&& d
->prod
[m
] != d
->cons
[m
] &&
178 be
->chr_can_read
&& be
->chr_can_read(be
->opaque
)) {
179 be
->chr_read(be
->opaque
,
180 &d
->buffer
[m
][d
->cons
[m
]++ & MUX_BUFFER_MASK
], 1);
184 static int mux_chr_can_read(void *opaque
)
186 MuxChardev
*d
= MUX_CHARDEV(opaque
);
188 CharBackend
*be
= d
->backends
[m
];
190 if ((d
->prod
[m
] - d
->cons
[m
]) < MUX_BUFFER_SIZE
) {
194 if (be
&& be
->chr_can_read
) {
195 return be
->chr_can_read(be
->opaque
);
201 static void mux_chr_read(void *opaque
, const uint8_t *buf
, int size
)
203 Chardev
*chr
= CHARDEV(opaque
);
204 MuxChardev
*d
= MUX_CHARDEV(opaque
);
206 CharBackend
*be
= d
->backends
[m
];
209 mux_chr_accept_input(opaque
);
211 for (i
= 0; i
< size
; i
++)
212 if (mux_proc_byte(chr
, d
, buf
[i
])) {
213 if (d
->prod
[m
] == d
->cons
[m
] &&
214 be
&& be
->chr_can_read
&&
215 be
->chr_can_read(be
->opaque
)) {
216 be
->chr_read(be
->opaque
, &buf
[i
], 1);
218 d
->buffer
[m
][d
->prod
[m
]++ & MUX_BUFFER_MASK
] = buf
[i
];
225 void mux_chr_send_all_event(Chardev
*chr
, int event
)
227 MuxChardev
*d
= MUX_CHARDEV(chr
);
230 if (!muxes_realized
) {
234 /* Send the event to all registered listeners */
235 for (i
= 0; i
< d
->mux_cnt
; i
++) {
236 mux_chr_send_event(d
, i
, event
);
240 static void mux_chr_event(void *opaque
, int event
)
242 mux_chr_send_all_event(CHARDEV(opaque
), event
);
245 static GSource
*mux_chr_add_watch(Chardev
*s
, GIOCondition cond
)
247 MuxChardev
*d
= MUX_CHARDEV(s
);
248 Chardev
*chr
= qemu_chr_fe_get_driver(&d
->chr
);
249 ChardevClass
*cc
= CHARDEV_GET_CLASS(chr
);
251 if (!cc
->chr_add_watch
) {
255 return cc
->chr_add_watch(chr
, cond
);
258 static void char_mux_finalize(Object
*obj
)
260 MuxChardev
*d
= MUX_CHARDEV(obj
);
263 for (i
= 0; i
< d
->mux_cnt
; i
++) {
264 CharBackend
*be
= d
->backends
[i
];
269 qemu_chr_fe_deinit(&d
->chr
, false);
272 void mux_chr_set_handlers(Chardev
*chr
, GMainContext
*context
)
274 MuxChardev
*d
= MUX_CHARDEV(chr
);
276 /* Fix up the real driver with mux routines */
277 qemu_chr_fe_set_handlers(&d
->chr
,
286 void mux_set_focus(Chardev
*chr
, int focus
)
288 MuxChardev
*d
= MUX_CHARDEV(chr
);
291 assert(focus
< d
->mux_cnt
);
293 if (d
->focus
!= -1) {
294 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_OUT
);
298 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_IN
);
301 static void qemu_chr_open_mux(Chardev
*chr
,
302 ChardevBackend
*backend
,
306 ChardevMux
*mux
= backend
->u
.mux
.data
;
308 MuxChardev
*d
= MUX_CHARDEV(chr
);
310 drv
= qemu_chr_find(mux
->chardev
);
312 error_setg(errp
, "mux: base chardev %s not found", mux
->chardev
);
317 /* only default to opened state if we've realized the initial
320 *be_opened
= muxes_realized
;
321 qemu_chr_fe_init(&d
->chr
, drv
, errp
);
324 static void qemu_chr_parse_mux(QemuOpts
*opts
, ChardevBackend
*backend
,
327 const char *chardev
= qemu_opt_get(opts
, "chardev");
330 if (chardev
== NULL
) {
331 error_setg(errp
, "chardev: mux: no chardev given");
334 backend
->type
= CHARDEV_BACKEND_KIND_MUX
;
335 mux
= backend
->u
.mux
.data
= g_new0(ChardevMux
, 1);
336 qemu_chr_parse_common(opts
, qapi_ChardevMux_base(mux
));
337 mux
->chardev
= g_strdup(chardev
);
340 static void char_mux_class_init(ObjectClass
*oc
, void *data
)
342 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
344 cc
->parse
= qemu_chr_parse_mux
;
345 cc
->open
= qemu_chr_open_mux
;
346 cc
->chr_write
= mux_chr_write
;
347 cc
->chr_accept_input
= mux_chr_accept_input
;
348 cc
->chr_add_watch
= mux_chr_add_watch
;
351 static const TypeInfo char_mux_type_info
= {
352 .name
= TYPE_CHARDEV_MUX
,
353 .parent
= TYPE_CHARDEV
,
354 .class_init
= char_mux_class_init
,
355 .instance_size
= sizeof(MuxChardev
),
356 .instance_finalize
= char_mux_finalize
,
359 static void register_types(void)
361 type_register_static(&char_mux_type_info
);
364 type_init(register_types
);