#include <stdbool.h>
#include <errno.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
#include <glib.h>
guint start_source;
guint host_source;
guint source;
+ int sock[2];
};
struct hciemu {
hciemu_debug_func_t debug_callback;
hciemu_destroy_func_t debug_destroy;
void *debug_data;
+
+ unsigned int flush_id;
};
struct hciemu_command_hook {
return NULL;
}
+ client->sock[0] = sv[0];
+ client->sock[1] = sv[1];
+
client->source = create_source_btdev(sv[0], client->dev);
client->host_source = create_source_bthost(sv[1], client->host);
client->start_source = g_idle_add(start_host, client);
queue_destroy(hciemu->post_command_hooks, destroy_command_hook);
queue_destroy(hciemu->clients, hciemu_client_destroy);
+ if (hciemu->flush_id)
+ g_source_remove(hciemu->flush_id);
+
vhci_close(hciemu->vhci);
free(hciemu);
return btdev_del_hook(dev, hook_type, opcode);
}
+
+static bool client_is_pending(const void *data, const void *match_data)
+{
+ struct hciemu_client *client = (struct hciemu_client *)data;
+ int used, i;
+
+ if (!client->source || !client->host_source)
+ return false;
+
+ for (i = 0; i < 2; ++i) {
+ if (!ioctl(client->sock[i], TIOCOUTQ, &used) && used > 0)
+ return true;
+ if (!ioctl(client->sock[i], TIOCINQ, &used) && used > 0)
+ return true;
+ }
+
+ return false;
+}
+
+static gboolean flush_client_events(gpointer user_data)
+{
+ struct hciemu *hciemu = user_data;
+
+ if (queue_find(hciemu->clients, client_is_pending, NULL))
+ return TRUE;
+
+ hciemu->flush_id = 0;
+
+ util_debug(hciemu->debug_callback, hciemu->debug_data, "vhci: resume");
+ if (hciemu->vhci)
+ vhci_pause_input(hciemu->vhci, false);
+
+ return FALSE;
+}
+
+void hciemu_flush_client_events(struct hciemu *hciemu)
+{
+ if (hciemu->flush_id || !hciemu->vhci)
+ return;
+
+ util_debug(hciemu->debug_callback, hciemu->debug_data, "vhci: pause");
+ vhci_pause_input(hciemu->vhci, true);
+ hciemu->flush_id = g_idle_add(flush_client_events, hciemu);
+}