From 7e8f5cb26ea2539b3c0dbbb9bdc4a99b0ec36ddf Mon Sep 17 00:00:00 2001 From: Jean Guyader Date: Fri, 21 Nov 2008 16:00:02 +0000 Subject: [PATCH] Fix the switch. You can use the command node to switch the keyboard only or both (mouse/keyboard). If you switch the mouse and the keyboard it will also change the focus to the new vm. To switch only the keyboard: write into /local/domain/0/dom0_driver "keyboard slot-id" To switch mouse and keyboard: write into /local/domain/0/dom0_driver "switch slot-id" Each vm owns a slot-id. It's the value of the dom0-input config option. --- dom0_driver.c | 119 ++++++++++++++++++++++++++++++++++++---------- qemu-xen.h | 13 ++++- xen-config-host.h | 7 --- xenstore.c | 62 +++++++++++++----------- 4 files changed, 139 insertions(+), 62 deletions(-) diff --git a/dom0_driver.c b/dom0_driver.c index 4291f00e..90fd78a4 100644 --- a/dom0_driver.c +++ b/dom0_driver.c @@ -25,6 +25,7 @@ #include "qemu-common.h" #include "console.h" #include "qemu-timer.h" +#include "qemu-xen.h" #include #include @@ -39,10 +40,12 @@ #include #include #include +#include extern int vga_passthrough; -void xenstore_watch_dom0_driver(const char *, const char *); +static void dom0_driver_state_change(const char *path, void *opaque); +static void dom0_driver_command(const char *path, void *opaque); #define DEBUG_DOM0_DRIVER 1 #define EVENT_PATH "/dev/input/event" @@ -82,6 +85,7 @@ struct dom0_driver_xs_info int domid; int leaving_dir; int new_slot; + int timestamp; }; static struct dom0_driver driver; @@ -104,7 +108,7 @@ static void dom0_driver_read_xs_info(struct dom0_driver_xs_info *info, char *str = NULL; char path[128]; int val[10]; - const char *key[] = {"state", "domid", "new-slot"}; + const char *key[] = {"state", "domid", "new-slot", "timestamp"}; memset(info, -1, sizeof (struct dom0_driver_xs_info)); for (int i = 0; i < sizeof (key) / sizeof (key[0]); i++) @@ -130,24 +134,27 @@ static void dom0_driver_read_xs_info(struct dom0_driver_xs_info *info, info->state = val[0]; info->domid = val[1]; info->new_slot = val[2]; + info->timestamp = val[3]; } static void dom0_driver_xs_write(const char *key, int val, int controller) { - char path[128]; + char path[128], str[10]; if (controller == DOM0_MOUSE) sprintf(path, "mouse/%s", key); if (controller == DOM0_KEYBOARD) sprintf(path, "keyboard/%s", key); - xenstore_write_dom0_driver(path, val); + sprintf(str, "%d", val); + xenstore_write_dom0_driver(path, str); } static int dom0_windows_key_switch(int code, int keycode) { int new_slot = 0; struct dom0_driver_xs_info info; + char buff[128]; dom0_driver_read_xs_info(&info, DOM0_MOUSE); if (info.state == 0) @@ -177,14 +184,10 @@ static int dom0_windows_key_switch(int code, int keycode) default: return 0; } + sprintf(buff, "switch %d", new_slot); - DEBUG("Write state = 0 inside xenstore\n"); - - dom0_driver_xs_write("new-slot", new_slot, DOM0_KEYBOARD); - dom0_driver_xs_write("new-slot", new_slot, DOM0_MOUSE); - - dom0_driver_xs_write("state", 0, DOM0_KEYBOARD); - dom0_driver_xs_write("state", 0, DOM0_MOUSE); + DEBUG("Write \"%s\" into xenstore\n", buff); + xenstore_write_dom0_driver("command", buff); return 1; } @@ -259,7 +262,7 @@ static void dom0_get_positions(int *positions) int *domids = NULL; int num; char *tmp; - unsigned long len; + unsigned int len; int pos = 0; memset(positions, 0, NB_SLOTS * 4); @@ -390,7 +393,12 @@ static void dom0_gr_devices(int grab, int controller) if (controller == DOM0_MOUSE) { if (vga_passthrough) - xenstore_write_dom0_driver("blank", !grab); + { + char str[10]; + + sprintf(str, "%d", !grab); + xenstore_write_dom0_driver("blank", str); + } else { struct dom0_driver_xs_info info; @@ -425,12 +433,13 @@ static int dom0_dom_alive(int id) static int dom0_driver_failover_switch(void *opaque) { - struct dom0_driver_xs_info info; + struct dom0_driver_xs_info mouse, keyboard; int ret = 1; - dom0_driver_read_xs_info(&info, DOM0_MOUSE); + dom0_driver_read_xs_info(&mouse, DOM0_MOUSE); + dom0_driver_read_xs_info(&keyboard, DOM0_KEYBOARD); - if (info.state == -1) + if (mouse.state == -1) { DEBUG("No state grab the device\n"); dom0_gr_devices(1, DOM0_KEYBOARD); @@ -439,14 +448,26 @@ static int dom0_driver_failover_switch(void *opaque) } /* The domain which has the focus crash */ - if (!dom0_dom_alive(info.domid)) + if (!dom0_dom_alive(mouse.domid)) { - DEBUG("steal the focus from %d\n", info.domid); + DEBUG("steal the focus from %d\n", mouse.domid); dom0_gr_devices(1, DOM0_KEYBOARD); dom0_gr_devices(1, DOM0_MOUSE); goto out; } + /* The domain is still alive but nobody grab the device + ** on the other side after 3 secondes */ + if (keyboard.state == 0 && keyboard.timestamp != -1 && + (time(NULL) - keyboard.timestamp) > 3) + dom0_gr_devices(1, DOM0_KEYBOARD); + if (mouse.state == 0 && keyboard.timestamp == -1 && + (time(NULL) - mouse.timestamp) > 3) + { + dom0_gr_devices(1, DOM0_MOUSE); + xenstore_write_dom0_driver("blank", "0"); + } + ret = 0; out: qemu_mod_timer(driver.xs_timer, qemu_get_clock(rt_clock) + XS_REFRESH_INTERVAL); @@ -514,11 +535,17 @@ static void dom0_driver_event_init(const char *str_arg) } if (vga_passthrough) - xenstore_write_dom0_driver("natif", domid); + { + char str[10]; + + sprintf(str, "%d", domid); + xenstore_write_dom0_driver("natif", str); + } - xenstore_watch_dom0_driver("mouse/state", "dom0_driver_keyboard_state"); - xenstore_watch_dom0_driver("keyboard/state", "dom0_driver_mouse_state"); - xenstore_watch_dom0_driver("blank", "dom0_driver_blank_done"); + xenstore_watch_dom0_driver("mouse/state", dom0_driver_state_change, NULL); + xenstore_watch_dom0_driver("keyboard/state", dom0_driver_state_change, NULL); + xenstore_watch_dom0_driver("blank", dom0_driver_state_change, NULL); + xenstore_watch_dom0_driver("command", dom0_driver_command, NULL); /* Register the failover switch */ driver.xs_timer = qemu_new_timer(rt_clock, dom0_driver_failover_switch, NULL); @@ -558,6 +585,46 @@ static void dom0_driver_slots(int controller) } } +static void dom0_driver_switch_controller(int slot, int controller) +{ + dom0_driver_xs_write("new-slot", slot, controller); + dom0_driver_xs_write("timestamp", time(NULL), controller); + dom0_driver_xs_write("state", 0, controller); +} + +void dom0_driver_command(const char *path, void *opaque) +{ + char *val = NULL; + + val = xenstore_read(path); + if (val == NULL) + return; + + if (!strncmp(val, "switch ", 7)) + { + int slot = strtol(val + 7, NULL, 10); + + if (errno == EINVAL) + goto out; + + DEBUG("switch the keyboard/mouse to slot %d\n", slot); + dom0_driver_switch_controller(slot, DOM0_KEYBOARD); + dom0_driver_switch_controller(slot, DOM0_MOUSE); + } + else if (!strncmp(val, "keyboard ", 9)) + { + int slot = strtol(val + 9, NULL, 10); + + if (errno == EINVAL) + goto out; + + DEBUG("switch the keyboard to slot %d\n", slot); + dom0_driver_switch_controller(slot, DOM0_KEYBOARD); + } +out: + free(val); +} + static void dom0_driver_blank_done(void) { struct dom0_driver_xs_info info; @@ -574,13 +641,13 @@ static void dom0_driver_blank_done(void) } } -void dom0_driver_state_change(const char *str) +static void dom0_driver_state_change(const char *path, void *opaque) { - if (!strcmp(str, "dom0_driver_keyboard_state")) + if (strstr(path, "/keyboard/state")) dom0_driver_slots(DOM0_KEYBOARD); - if (!strcmp(str, "dom0_driver_mouse_state")) + if (strstr(path, "/mouse/state")) dom0_driver_slots(DOM0_MOUSE); - if (!strcmp(str, "dom0_driver_blank_done")) + if (strstr(path, "/blank")) dom0_driver_blank_done(); } diff --git a/qemu-xen.h b/qemu-xen.h index 03ce13b0..047f6985 100644 --- a/qemu-xen.h +++ b/qemu-xen.h @@ -44,9 +44,9 @@ void handle_buffered_pio(void); #endif /* xenstore.c */ -typedef void (*xenstore_callback) (const char *token, void *opaque); +typedef void (*xenstore_callback) (const char *path, void *opaque); int xenstore_watch_screenshot_node(DisplayState *ds); -void xenstore_watch_callback(const char *token, xenstore_callback fptr, void *opaque); +int xenstore_watch_new_callback(const char *path, xenstore_callback fptr, void *opaque); void xenstore_parse_domain_config(int domid); int xenstore_fd(void); void xenstore_process_event(void *opaque); @@ -76,6 +76,15 @@ int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle, const char *devtype, const char *inst, const char *token); +char *xenstore_read_dom0_driver(const char *key); +int xenstore_write_dom0_driver(const char *key, const char *str); +int xenstore_watch_dom0_driver(const char *key, xenstore_callback fptr, void *opaque); + +char *xenstore_dom_read(int domid, char *key, unsigned int *len); +int xenstore_dom_write(int domid, char *key, char *value); + +int *xenstore_get_domids(int *len); +char *xenstore_read(const char *path); /* `danger' means that this parameter, variable or function refers to * an area of xenstore which is writeable by the guest and thus must diff --git a/xen-config-host.h b/xen-config-host.h index e8782d54..c6da4b3a 100644 --- a/xen-config-host.h +++ b/xen-config-host.h @@ -46,10 +46,3 @@ extern struct BlockDriver bdrv_vbd; struct CharDriverState; void xenstore_store_serial_port_info(int i, struct CharDriverState *chr, const char *devname); -char *xenstore_read_dom0_driver(const char *key); -int xenstore_write_dom0_driver(const char *key, int val); - -char *xenstore_dom_read(int domid, char *key, unsigned int *len); -int xenstore_dom_write(int domid, char *key, char *value); - -int *xenstore_get_domids(int *len); diff --git a/xenstore.c b/xenstore.c index 1f065551..260fbcb8 100644 --- a/xenstore.c +++ b/xenstore.c @@ -43,32 +43,39 @@ static QEMUTimer *insert_timer = NULL; struct xenstore_watch_cb_t { - char *token; + char *path; xenstore_callback cb; void *opaque; }; static struct xenstore_watch_cb_t *xenstore_watch_callbacks = NULL; -void xenstore_watch_callback(const char *token, xenstore_callback fptr, void *opaque) +int xenstore_watch_new_callback(const char *path, + xenstore_callback fptr, + void *opaque) { - int i = 0; + int i = 0, ret = 0; + + ret = xs_watch(xsh, path, path); + if (ret == 0) + return 0; if (!xenstore_watch_callbacks) { xenstore_watch_callbacks = malloc(sizeof (struct xenstore_watch_cb_t)); - xenstore_watch_callbacks[0].token = NULL; + xenstore_watch_callbacks[0].path = NULL; } - while (xenstore_watch_callbacks[i].token) + while (xenstore_watch_callbacks[i].path) i++; xenstore_watch_callbacks = realloc(xenstore_watch_callbacks, (i + 2) * sizeof (struct xenstore_watch_cb_t)); - xenstore_watch_callbacks[i].token = strdup(token); + xenstore_watch_callbacks[i].path = strdup(path); xenstore_watch_callbacks[i].cb = fptr; xenstore_watch_callbacks[i].opaque = opaque; - xenstore_watch_callbacks[i + 1].token = NULL; + xenstore_watch_callbacks[i + 1].path = NULL; + return ret; } static int pasprintf(char **buf, const char *fmt, ...) @@ -829,10 +836,13 @@ void xenstore_process_event(void *opaque) if (!vec) return; - for (i = 0; xenstore_watch_callbacks && xenstore_watch_callbacks[i].token; i++) - if (!strcmp(vec[XS_WATCH_TOKEN], xenstore_watch_callbacks[i].token)) + for (i = 0; xenstore_watch_callbacks && xenstore_watch_callbacks[i].path; i++) + if (!strcmp(vec[XS_WATCH_TOKEN], xenstore_watch_callbacks[i].path)) + { + fprintf(stderr, "xenstore_callback: call %s\n", vec[XS_WATCH_TOKEN]); xenstore_watch_callbacks[i].cb(vec[XS_WATCH_TOKEN], xenstore_watch_callbacks[i].opaque); + } if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) { xenstore_process_logdirty_event(); @@ -844,14 +854,6 @@ void xenstore_process_event(void *opaque) goto out; } - if (!strcmp(vec[XS_WATCH_TOKEN], "dom0_driver_keyboard_state") || - !strcmp(vec[XS_WATCH_TOKEN], "dom0_driver_mouse_state") || - !strcmp(vec[XS_WATCH_TOKEN], "dom0_driver_blank_done")) - { - dom0_driver_state_change(vec[XS_WATCH_TOKEN]); - goto out; - } - if (!strcmp(vec[XS_WATCH_TOKEN], "acadapterstatechangeevt")) { acpi_ac_adapter_state_changed(); goto out; @@ -1417,7 +1419,7 @@ char *xenstore_read_dom0_driver(const char *key) return val; } -int xenstore_watch_dom0_driver(const char *key, const char *token) +int xenstore_watch_dom0_driver(const char *key, xenstore_callback fptr, void *opaque) { const char *path = "/local/domain/0/dom0_driver"; char *buf = NULL; @@ -1425,22 +1427,20 @@ int xenstore_watch_dom0_driver(const char *key, const char *token) if (pasprintf(&buf, "%s/%s", path, key) == -1) return 0; - ret = xs_watch(xsh, buf, token); + xenstore_watch_new_callback(buf, fptr, opaque); free(buf); return ret; } -int xenstore_write_dom0_driver(const char *key, int val) +int xenstore_write_dom0_driver(const char *key, const char *str) { const char *path = "/local/domain/0/dom0_driver"; char *buf = NULL; int len = 0; - char str[10]; int ret = 0; if (pasprintf(&buf, "%s/%s", path, key) == -1) return 0; - sprintf(str, "%d", val); ret = xs_write(xsh, XBT_NULL, buf, str, strlen(str)); free(buf); return ret; @@ -1517,9 +1517,6 @@ int *xenstore_get_domids(int *len) return tab; } - -/* Advertise through xenstore that the device model is up and the - domain can be started. */ void xenstore_dm_finished_startup(void) { char *path; @@ -1583,11 +1580,22 @@ int xenstore_watch_screenshot_node(DisplayState *ds) fprintf(logfile, "pasprintf failed to get path.\n"); goto out; } - xenstore_watch_callback("screenshot", xenstore_screenshot, ds); fprintf(stderr, "screenshot watch node %s\n", buf); - ret = xs_watch(xsh, buf, "screenshot"); + ret = xenstore_watch_new_callback(buf, xenstore_screenshot, ds); out: free(buf); free(path); return ret; } + +char *xenstore_read(const char *path) +{ + char *value = NULL; + unsigned int len; + + if (xsh == NULL) + return NULL; + return xs_read(xsh, XBT_NULL, path, &len); +} + + -- 2.39.5