X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=linux_module%2Fiface-graphics-console.c;h=6744cfd5bcc04b279bebb89374758433873ae496;hb=2cb41f7db5b9f89113432d6b3daff4807ba8e5f2;hp=227e90eaa3a1f47db19583f55d6fc5c65a27d7d9;hpb=276cfa264720edddc1677e35c6a300596965de7d;p=palacios.git diff --git a/linux_module/iface-graphics-console.c b/linux_module/iface-graphics-console.c index 227e90e..6744cfd 100644 --- a/linux_module/iface-graphics-console.c +++ b/linux_module/iface-graphics-console.c @@ -22,7 +22,6 @@ #include "linux-exts.h" #include "vm.h" -#include /* @@ -41,6 +40,7 @@ */ +static struct list_head global_gcons; struct palacios_graphics_console { // descriptor for the data in the shared frame buffer @@ -56,10 +56,19 @@ struct palacios_graphics_console { uint32_t num_updates; - // Currently keystrokes and mouse movements are ignored + int change_request; + + int (*render_request)(v3_graphics_console_t cons, + void *priv_data); + void *render_data; + + int (*update_inquire)(v3_graphics_console_t cons, + void *priv_data); + + void *update_data; + + struct list_head gcons_node; - // currently, we will not worry about locking this - // lock_t ... }; @@ -78,12 +87,12 @@ static v3_graphics_console_t g_open(void * priv_data, gc = get_vm_ext_data(guest, "GRAPHICS_CONSOLE_INTERFACE"); if (gc == NULL) { - printk("palacios: Could not locate graphics console data for extension GRAPHICS_CONSOLE_INTERFACE\n"); + ERROR("palacios: Could not locate graphics console data for extension GRAPHICS_CONSOLE_INTERFACE\n"); return 0; } if (gc->data != NULL) { - printk("palacios: framebuffer already allocated - returning it\n"); + DEBUG("palacios: framebuffer already allocated - returning it\n"); *actual_spec = gc->spec; gc->cons_refcount++; @@ -94,13 +103,13 @@ static v3_graphics_console_t g_open(void * priv_data, mem = desired_spec->width * desired_spec->height * desired_spec->bytes_per_pixel; - printk("palacios: allocating %u bytes for %u by %u by %u buffer\n", + DEBUG("palacios: allocating %u bytes for %u by %u by %u buffer\n", mem, desired_spec->width, desired_spec->height, desired_spec->bytes_per_pixel); - gc->data = vmalloc(mem); + gc->data = palacios_valloc(mem); if (!(gc->data)) { - printk("palacios: unable to allocate memory for frame buffer\n"); + ERROR("palacios: unable to allocate memory for frame buffer\n"); return 0; } @@ -112,7 +121,7 @@ static v3_graphics_console_t g_open(void * priv_data, gc->cons_refcount++; gc->data_refcount++; - printk("palacios: allocated frame buffer\n"); + INFO("palacios: allocated frame buffer\n"); return gc; } @@ -125,21 +134,21 @@ static void g_close(v3_graphics_console_t cons) gc->data_refcount--; if (gc->data_refcount < gc->cons_refcount) { - printk("palacios: error! data refcount is less than console refcount for graphics console\n"); + ERROR("palacios: error! data refcount is less than console refcount for graphics console\n"); } if (gc->cons_refcount > 0) { return; } else { if (gc->cons_refcount < 0) { - printk("palacios: error! refcount for graphics console is negative on close!\n"); + ERROR("palacios: error! refcount for graphics console is negative on close!\n"); } if (gc->data_refcount > 0) { - printk("palacios: error! refcount for graphics console data is positive on close - LEAKING MEMORY\n"); + ERROR("palacios: error! refcount for graphics console data is positive on close - LEAKING MEMORY\n"); return; } if (gc->data) { - kfree(gc->data); + palacios_vfree(gc->data); gc->data=0; } } @@ -151,7 +160,7 @@ static void * g_get_data_read(v3_graphics_console_t cons, struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons; if (gc->data_refcount<=0) { - printk("palacios: error! data refcount is <= 0 in get_data_read\n"); + ERROR("palacios: error! data refcount is <= 0 in get_data_read\n"); } gc->data_refcount++; @@ -168,7 +177,7 @@ static void g_release_data_read(v3_graphics_console_t cons) gc->data_refcount--; if (gc->data_refcount<=0) { - printk("palacios: error! data refcount is <= zero in release_data_read\n"); + ERROR("palacios: error! data refcount is <= zero in release_data_read\n"); } } @@ -189,43 +198,88 @@ static void g_release_data_rw(v3_graphics_console_t cons) static int g_changed(v3_graphics_console_t cons) { -#if 0 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons; + int cr; + + cr = gc->change_request; + + gc->change_request=0; - int rc = !(gc->num_updates % 1000); - gc->num_updates++; - return rc; -#else - return 1; -#endif + return cr; + } +static int g_register_render_request( + v3_graphics_console_t cons, + int (*render_request)(v3_graphics_console_t, + void *), + void *priv_data) +{ + struct palacios_graphics_console *gc = + (struct palacios_graphics_console *) cons; + + gc->render_data = priv_data; + gc->render_request = render_request; + + INFO("palacios: installed rendering callback function for graphics console\n"); + + return 0; + +} + +static int g_register_update_inquire( + v3_graphics_console_t cons, + int (*update_inquire)(v3_graphics_console_t, + void *), + void *priv_data) +{ + struct palacios_graphics_console *gc = + (struct palacios_graphics_console *) cons; + + gc->update_data = priv_data; + gc->update_inquire = update_inquire; + + INFO("palacios: installed update inquiry callback function for graphics console\n"); + + return 0; + +} static int palacios_graphics_console_key(struct v3_guest * guest, struct palacios_graphics_console *cons, uint8_t scancode) { - struct v3_keyboard_event e; + struct v3_keyboard_event e; e.status = 0; e.scan_code = scancode; + //DEBUG("palacios: start key delivery\n"); + v3_deliver_keyboard_event(guest->v3_ctx, &e); + + //DEBUG("palacios: end key delivery\n"); return 0; } static int palacios_graphics_console_mouse(struct v3_guest * guest, struct palacios_graphics_console *cons, - uint8_t x, uint8_t y, uint8_t buttons) + uint8_t sx, uint8_t dx, + uint8_t sy, uint8_t dy, + uint8_t buttons) { + struct v3_mouse_event e; - e.data[0]=x; - e.data[1]=y; - e.data[2]=buttons; // These three are completely wrong, of course - ignoring mouse for now + + e.sx=sx; + e.dx=dx; + e.sy=sy; + e.dy=dy; + e.buttons=buttons; v3_deliver_mouse_event(guest->v3_ctx,&e); @@ -243,17 +297,37 @@ static struct v3_graphics_console_hooks palacios_graphics_console_hooks = .release_data_rw = g_release_data_rw, .changed = g_changed, + .register_render_request = g_register_render_request, + .register_update_inquire = g_register_update_inquire, }; static int graphics_console_init( void ) { + INIT_LIST_HEAD(&(global_gcons)); + V3_Init_Graphics_Console(&palacios_graphics_console_hooks); return 0; } +static int graphics_console_deinit( void ) { + struct palacios_graphics_console * gc = NULL; + struct palacios_graphics_console * tmp = NULL; + + list_for_each_entry_safe(gc, tmp, &(global_gcons), gcons_node) { + list_del(&(gc->gcons_node)); + + if (gc->data) + palacios_vfree(gc->data); + + palacios_free(gc); + } + + return 0; +} + static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data) { @@ -262,27 +336,36 @@ static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg if (copy_from_user(&q, (void __user *) arg, sizeof(struct v3_fb_query_response))) { - printk("palacios: copy from user in getting query in fb\n"); + ERROR("palacios: copy from user in getting query in fb\n"); return -EFAULT; } switch (q.request_type) { case V3_FB_SPEC: + //INFO("palacios: request for db spec from Userland\n"); // returns only the spec for the FB q.spec = cons->spec; break; case V3_FB_UPDATE: + //DEBUG("palacios: test for fb updatei from Userland\n"); // returns whether an update is available for the region - // currently always true - q.updated = 1; + if (cons->update_inquire) { + q.updated = cons->update_inquire(cons,cons->update_data); + } else { + q.updated = 1; + } + //DEBUG("palacios: update=%d\n",q.updated); + + // request a render, since a FB_DATA will probably soon come + cons->change_request = 1; break; case V3_FB_DATA_BOX: { // Not curently implemented - printk("palacios: request for data in bounding box unsupported currently\n"); + ERROR("palacios: request for data in bounding box unsupported currently\n"); return -EFAULT; } @@ -290,18 +373,28 @@ static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg break; case V3_FB_DATA_ALL: { + //DEBUG("palacios: got FrameBuffer Request from Userland\n"); // First let's sanity check to see if they are requesting the same // spec that we have if (memcmp(&(q.spec),&(cons->spec),sizeof(struct v3_frame_buffer_spec))) { - printk("palacios: request for data with non-matching fb spec \n"); + ERROR("palacios: request for data with non-matching fb spec \n"); return -EFAULT; } + // Now we will force a render if we can + if (cons->render_request) { + //DEBUG("palacios: making rendering request\n"); + cons->render_request(cons,cons->render_data); + } + // Now let's indicate an update is in the pointer and copy across the data if (copy_to_user(q.data,cons->data,cons->spec.width*cons->spec.height*cons->spec.bytes_per_pixel)) { - printk("palacios: unable to copy fb content to user\n"); + ERROR("palacios: unable to copy fb content to user\n"); return -EFAULT; } + //DEBUG("palacios: FrameBuffer copy out done\n"); q.updated = 1; + // Now we don't need to request a render + cons->change_request = 0; } break; @@ -311,7 +404,7 @@ static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg // now we'll copy back any changes we made to the query/response structure if (copy_to_user((void __user *) arg, (void*)&q, sizeof(struct v3_fb_query_response))) { - printk("palacios: unable to copy fb response to user\n"); + ERROR("palacios: unable to copy fb response to user\n"); return -EFAULT; } @@ -330,32 +423,36 @@ static int fb_input(struct v3_guest * guest, if (copy_from_user(&inp, (void __user *) arg, sizeof(struct v3_fb_input))) { - printk("palacios: copy from user in getting input in fb\n"); + ERROR("palacios: copy from user in getting input in fb\n"); return -EFAULT; } + + //DEBUG("palacios: input from Userland\n"); if ((inp.data_type == V3_FB_KEY) || (inp.data_type == V3_FB_BOTH)) { rc = palacios_graphics_console_key(guest, cons, inp.scan_code); + //DEBUG("palacios: key delivered to palacios\n"); } if ((inp.data_type == V3_FB_MOUSE) || (inp.data_type == V3_FB_BOTH)) { - rc |= palacios_graphics_console_mouse(guest, cons, inp.mouse_data[0], - inp.mouse_data[1], inp.mouse_data[2]); + rc |= palacios_graphics_console_mouse(guest, cons, inp.sx, inp.dx, inp.sy, inp.dy, inp.buttons); + //DEBUG("palacios: mouse delivered to palacios\n"); } if (rc) { return -EFAULT; } else { + cons->change_request=1; return 0; } } static int graphics_console_guest_init(struct v3_guest * guest, void ** vm_data) { - struct palacios_graphics_console * graphics_cons = kmalloc(sizeof(struct palacios_graphics_console), GFP_KERNEL); + struct palacios_graphics_console * graphics_cons = palacios_alloc(sizeof(struct palacios_graphics_console)); if (!graphics_cons) { - printk("palacios: filed to do guest_init for graphics console\n"); + ERROR("palacios: filed to do guest_init for graphics console\n"); return -1; } @@ -366,17 +463,38 @@ static int graphics_console_guest_init(struct v3_guest * guest, void ** vm_data) add_guest_ctrl(guest, V3_VM_FB_INPUT, fb_input, graphics_cons); add_guest_ctrl(guest, V3_VM_FB_QUERY, fb_query, graphics_cons); + list_add(&(graphics_cons->gcons_node),&global_gcons); + return 0; } +static int graphics_console_guest_deinit(struct v3_guest * guest, void * vm_data) { + struct palacios_graphics_console * graphics_cons = (struct palacios_graphics_console *)vm_data; + + list_del(&(graphics_cons->gcons_node)); + + remove_guest_ctrl(guest, V3_VM_FB_INPUT); + remove_guest_ctrl(guest, V3_VM_FB_QUERY); + + if (graphics_cons->data) { + palacios_vfree(graphics_cons->data); + } + + + palacios_free(graphics_cons); + + return 0; +} + + static struct linux_ext graphics_cons_ext = { .name = "GRAPHICS_CONSOLE_INTERFACE", .init = graphics_console_init, - .deinit = NULL, + .deinit = graphics_console_deinit, .guest_init = graphics_console_guest_init, - .guest_deinit = NULL + .guest_deinit = graphics_console_guest_deinit, };