+CharDriverState *qemu_chr_fe_get_driver(CharBackend *be)
+{
+ return be->chr;
+}
+
+bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
+{
+ int tag = 0;
+
+ if (s->is_mux) {
+ MuxDriver *d = s->opaque;
+
+ if (d->mux_cnt >= MAX_MUX) {
+ goto unavailable;
+ }
+
+ d->backends[d->mux_cnt] = b;
+ tag = d->mux_cnt++;
+ } else if (s->be) {
+ goto unavailable;
+ } else {
+ s->be = b;
+ }
+
+ b->fe_open = false;
+ b->tag = tag;
+ b->chr = s;
+ return true;
+
+unavailable:
+ error_setg(errp, QERR_DEVICE_IN_USE, s->label);
+ return false;
+}
+
+static bool qemu_chr_is_busy(CharDriverState *s)
+{
+ if (s->is_mux) {
+ MuxDriver *d = s->opaque;
+ return d->mux_cnt >= 0;
+ } else {
+ return s->be != NULL;
+ }
+}
+
+void qemu_chr_fe_deinit(CharBackend *b)
+{
+ assert(b);
+
+ if (b->chr) {
+ qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
+ b->chr->be = NULL;
+ if (b->chr->is_mux) {
+ MuxDriver *d = b->chr->opaque;
+ d->backends[b->tag] = NULL;
+ }
+ b->chr = NULL;
+ }
+}
+
+void qemu_chr_fe_set_handlers(CharBackend *b,
+ IOCanReadHandler *fd_can_read,
+ IOReadHandler *fd_read,
+ IOEventHandler *fd_event,
+ void *opaque,
+ GMainContext *context,
+ bool set_open)
+{
+ CharDriverState *s;
+ int fe_open;
+
+ s = b->chr;
+ if (!s) {
+ return;
+ }
+
+ if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+ fe_open = 0;
+ remove_fd_in_watch(s);
+ } else {
+ fe_open = 1;
+ }
+ b->chr_can_read = fd_can_read;
+ b->chr_read = fd_read;
+ b->chr_event = fd_event;
+ b->opaque = opaque;
+ if (s->chr_update_read_handler) {
+ s->chr_update_read_handler(s, context);
+ }
+
+ if (set_open) {
+ qemu_chr_fe_set_open(b, fe_open);
+ }
+
+ if (fe_open) {
+ qemu_chr_fe_take_focus(b);
+ /* We're connecting to an already opened device, so let's make sure we
+ also get the open event */
+ if (s->be_open) {
+ qemu_chr_be_generic_open(s);
+ }
+ }
+
+ if (s->is_mux) {
+ mux_chr_set_handlers(s, context);
+ }
+}
+
+void qemu_chr_fe_take_focus(CharBackend *b)
+{
+ if (!b->chr) {
+ return;
+ }
+
+ if (b->chr->is_mux) {
+ mux_set_focus(b->chr->opaque, b->tag);
+ }
+}