Hi,
my domain hangs when I load xenfb module.
The sequence is:
dom0# sdlfb <id>
...
domU# modprobe fbcon
domU# modprobe xenkbd
domU# modprobe xenfb
... HANGS HERE ....
I found that it hangs in xenfb_event_handler() because info->page->in_prod and
info->page->in_cons are not initialized correctly.
I propose following correction:
Index: xen-3.0-testing.hg/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c
===================================================================
--- xen-3.0-testing.hg.orig/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c
2006-07-28 12:58:47.000000000 +0200
+++ xen-3.0-testing.hg/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c
2006-07-28 15:28:23.000000000 +0200
@@ -414,6 +414,8 @@
info->page->depth = 32;
info->page->line_length = (info->page->depth / 8) * info->page->width;
info->page->mem_length = xenfb_mem_len;
+ info->page->in_cons = info->page->in_prod = 0;
+ info->page->out_cons = info->page->out_prod = 0;
ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
0, "xenfb", info);
Regards,
Laurent
Markus Armbruster wrote:
> Derived from
> http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle
>
> Converted to Xenstore and ported to current kernels.
>
> Signed-off-by: Markus Armbruster <armbru@xxxxxxxxxx>
>
>
> diff -r d8434a6fdd05 arch/i386/kernel/setup-xen.c
> --- a/arch/i386/kernel/setup-xen.c Fri Jun 16 19:34:13 2006 +0200
> +++ b/arch/i386/kernel/setup-xen.c Fri Jun 23 10:07:51 2006 +0200
> @@ -1787,8 +1787,12 @@ void __init setup_arch(char **cmdline_p)
> #endif
> #endif
> } else {
> +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
> + conswitchp = &dummy_con;
> +#else
> extern int console_use_vt;
> console_use_vt = 0;
> +#endif
> }
> }
>
> diff -r d8434a6fdd05 drivers/xen/Kconfig
> --- a/drivers/xen/Kconfig Fri Jun 16 19:34:13 2006 +0200
> +++ b/drivers/xen/Kconfig Fri Jun 23 10:07:51 2006 +0200
> @@ -173,6 +173,29 @@ config XEN_BLKDEV_TAP
> to a character device, allowing device prototyping in application
> space. Odds are that you want to say N here.
>
> +config XEN_FRAMEBUFFER
> + tristate "Framebuffer-device frontend driver"
> + depends on XEN && FB
> + select FB_CFB_FILLRECT
> + select FB_CFB_COPYAREA
> + select FB_CFB_IMAGEBLIT
> + default y
> + help
> + The framebuffer-device frontend drivers allows the kernel to create a
> + virtual framebuffer. This framebuffer can be viewed in another
> + domain. Unless this domain has access to a real video card, you
> + probably want to say Y here.
> +
> +config XEN_KEYBOARD
> + tristate "Keyboard-device frontend driver"
> + depends on XEN
> + default y
> + help
> + The keyboard-device frontend driver allows the kernel to create a
> + virtual keyboard. This keyboard can then be driven by another
> + domain. If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably
> + want to say Y here.
> +
> config XEN_SCRUB_PAGES
> bool "Scrub memory before freeing it to Xen"
> default y
> diff -r d8434a6fdd05 drivers/xen/Makefile
> --- a/drivers/xen/Makefile Fri Jun 16 19:34:13 2006 +0200
> +++ b/drivers/xen/Makefile Fri Jun 23 10:07:51 2006 +0200
> @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_TAP) += blkt
> obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/
> obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/
> obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/
> +obj-$(CONFIG_XEN_FRAMEBUFFER) += xenfb/
> +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd/
> diff -r d8434a6fdd05 drivers/xen/xenfb/Makefile
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/drivers/xen/xenfb/Makefile Fri Jun 23 10:07:51 2006 +0200
> @@ -0,0 +1,1 @@
> +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o
> diff -r d8434a6fdd05 drivers/xen/xenfb/xenfb.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/drivers/xen/xenfb/xenfb.c Fri Jun 23 10:07:51 2006 +0200
> @@ -0,0 +1,579 @@
> +/*
> + * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
> + *
> + * Copyright (C) 2005-2006
> + *
> + * Anthony Liguori <aliguori@xxxxxxxxxx>
> + *
> + * Based on linux/drivers/video/q40fb.c
> + *
> + * This file is subject to the terms and conditions of the GNU General
> Public
> + * License. See the file COPYING in the main directory of this archive for
> + * more details.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/fb.h>
> +#include <linux/module.h>
> +#include <linux/vmalloc.h>
> +#include <linux/mm.h>
> +#include <asm/hypervisor.h>
> +#include <xen/evtchn.h>
> +#include <xen/xenbus.h>
> +#include <linux/xenfb.h>
> +#include <linux/kthread.h>
> +
> +static int xenfb_fps = 20;
> +static unsigned long xenfb_mem_len = 2 * 1024 * 1024;
> +
> +struct xenfb_mapping
> +{
> + struct list_head next;
> + struct vm_area_struct *vma;
> + atomic_t map_refs;
> + int faults;
> + struct xenfb_info *info;
> +};
> +
> +struct xenfb_info
> +{
> + struct task_struct *kthread;
> + wait_queue_head_t wq;
> +
> + unsigned char *fb;
> + struct fb_fix_screeninfo *fix;
> + struct fb_var_screeninfo *var;
> + struct fb_info *fb_info;
> + struct timer_list refresh;
> + int dirty;
> + int y1, y2;
> + int x1, x2;
> +
> + struct semaphore mm_lock;
> + int nr_pages;
> + struct page **pages;
> + struct list_head mappings;
> +
> + unsigned evtchn;
> + struct xenfb_page *page;
> + unsigned long *mfns;
> +};
> +
> +static void xenfb_do_update(struct xenfb_info *info,
> + int x, int y, int w, int h)
> +{
> + union xenfb_out_event event;
> + __u32 cons, prod;
> +
> + event.type = XENFB_TYPE_UPDATE;
> + event.update.x = x;
> + event.update.y = y;
> + event.update.width = w;
> + event.update.height = h;
> +
> + /* FIXME barriers */
> + prod = XENFB_MASK_RING(info->page->out_prod, info->page->out);
> + cons = XENFB_MASK_RING(info->page->out_cons, info->page->out);
> + prod = XENFB_MASK_RING(prod + 1, info->page->out);
> +
> + if (prod == cons)
> + return;
> +
> + memcpy(&info->page->out[prod], &event, sizeof(event));
> + info->page->out_prod = prod;
> +
> + notify_remote_via_evtchn(info->evtchn);
> +}
> +
> +static int xenfb_queue_full(struct xenfb_info *info)
> +{
> + __u32 cons, prod;
> +
> + prod = XENFB_MASK_RING(info->page->out_prod, info->page->out);
> + cons = XENFB_MASK_RING(info->page->out_cons, info->page->out);
> + prod = XENFB_MASK_RING(prod + 1, info->page->out);
> +
> + return (prod == cons);
> +}
> +
> +static void xenfb_update_screen(struct xenfb_info *info)
> +{
> + int y1, y2, x1, x2;
> + struct list_head *item;
> + struct xenfb_mapping *map;
> +
> + if (xenfb_queue_full(info))
> + return;
> +
> + y1 = info->y1;
> + y2 = info->y2;
> + x1 = info->x1;
> + x2 = info->x2;
> + info->dirty = info->y1 = info->y2 = info->x1 = info->x2 = 0;
> + down(&info->mm_lock);
> + list_for_each(item, &info->mappings) {
> + map = list_entry(item, struct xenfb_mapping, next);
> + if (!map->faults)
> + continue;
> + zap_page_range(map->vma, map->vma->vm_start,
> + map->vma->vm_end - map->vma->vm_start, NULL);
> + map->faults = 0;
> + }
> + up(&info->mm_lock);
> +
> + xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
> +}
> +
> +static int xenfb_thread(void *data)
> +{
> + struct xenfb_info *info = data;
> + DECLARE_WAITQUEUE(wait, current);
> +
> + add_wait_queue(&info->wq, &wait);
> + for (;;) {
> + if (kthread_should_stop())
> + break;
> + if (info->dirty)
> + xenfb_update_screen(info);
> + set_current_state(TASK_INTERRUPTIBLE);
> + schedule();
> + }
> + remove_wait_queue(&info->wq, &wait);
> + return 0;
> +}
> +
> +static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
> + unsigned blue, unsigned transp,
> + struct fb_info *info)
> +{
> + u32 v;
> +
> + if (regno > info->cmap.len)
> + return 1;
> +
> + red >>= (16 - info->var.red.length);
> + green >>= (16 - info->var.green.length);
> + blue >>= (16 - info->var.blue.length);
> +
> + v = (red << info->var.red.offset) |
> + (green << info->var.green.offset) |
> + (blue << info->var.blue.offset);
> +
> + switch (info->var.bits_per_pixel) {
> + case 16:
> + case 24:
> + case 32:
> + ((u32 *)info->pseudo_palette)[regno] = v;
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static void xenfb_timer(unsigned long data)
> +{
> + struct xenfb_info *info = (struct xenfb_info *)data;
> + info->dirty++;
> + wake_up(&info->wq);
> +}
> +
> +static void xenfb_refresh(struct xenfb_info *info,
> + int x1, int y1, int w, int h)
> +{
> + int y2, x2;
> +
> + y2 = y1 + h;
> + x2 = x1 + w;
> + if (info->y2 == 0) {
> + info->y1 = y1;
> + info->y2 = y2;
> + }
> + if (info->x2 == 0) {
> + info->x1 = x1;
> + info->x2 = x2;
> + }
> +
> + if (info->y1 > y1)
> + info->y1 = y1;
> + if (info->y2 < y2)
> + info->y2 = y2;
> + if (info->x1 > x1)
> + info->x1 = x1;
> + if (info->x2 < x2)
> + info->x2 = x2;
> +
> + if (timer_pending(&info->refresh))
> + return;
> +
> + mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
> +}
> +
> +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
> +{
> + struct xenfb_info *info = p->par;
> +
> + cfb_fillrect(p, rect);
> + xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
> +}
> +
> +static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
> +{
> + struct xenfb_info *info = p->par;
> +
> + cfb_imageblit(p, image);
> + xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
> +}
> +
> +static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
> +{
> + struct xenfb_info *info = p->par;
> +
> + cfb_copyarea(p, area);
> + xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
> +}
> +
> +static void xenfb_vm_open(struct vm_area_struct *vma)
> +{
> + struct xenfb_mapping *map = vma->vm_private_data;
> + atomic_inc(&map->map_refs);
> +}
> +
> +static void xenfb_vm_close(struct vm_area_struct *vma)
> +{
> + struct xenfb_mapping *map = vma->vm_private_data;
> + struct xenfb_info *info = map->info;
> +
> + down(&info->mm_lock);
> + if (atomic_dec_and_test(&map->map_refs)) {
> + list_del(&map->next);
> + kfree(map);
> + }
> + up(&info->mm_lock);
> +}
> +
> +static struct page *xenfb_vm_nopage(struct vm_area_struct *vma,
> + unsigned long vaddr, int *type)
> +{
> + struct xenfb_mapping *map = vma->vm_private_data;
> + struct xenfb_info *info = map->info;
> + int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
> + struct page *page;
> + int y1, y2;
> +
> + if (pgnr >= info->nr_pages)
> + return NOPAGE_SIGBUS;
> +
> + down(&info->mm_lock);
> + page = info->pages[pgnr];
> + get_page(page);
> + map->faults++;
> +
> + y1 = pgnr * PAGE_SIZE / info->fix->line_length;
> + y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fix->line_length;
> + if (y2 > info->var->yres)
> + y2 = info->var->yres;
> + xenfb_refresh(info, 0, y1, info->var->xres, y2 - y1);
> + up(&info->mm_lock);
> +
> + if (type)
> + *type = VM_FAULT_MINOR;
> +
> + return page;
> +}
> +
> +static struct vm_operations_struct xenfb_vm_ops = {
> + .open = xenfb_vm_open,
> + .close = xenfb_vm_close,
> + .nopage = xenfb_vm_nopage,
> +};
> +
> +static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma)
> +{
> + struct xenfb_info *info = fb_info->par;
> + struct xenfb_mapping *map;
> + int ret;
> + int map_pages;
> +
> + down(&info->mm_lock);
> +
> + ret = -EINVAL;
> + if (!(vma->vm_flags & VM_WRITE))
> + goto out;
> + if (!(vma->vm_flags & VM_SHARED))
> + goto out;
> + if (vma->vm_pgoff != 0)
> + goto out;
> +
> + map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
> + if (map_pages > info->nr_pages)
> + goto out;
> +
> + ret = -ENOMEM;
> + map = kmalloc(sizeof(*map), GFP_KERNEL);
> + if (map == NULL)
> + goto out;
> + memset(map, 0, sizeof(*map));
> +
> + map->vma = vma;
> + map->faults = 0;
> + map->info = info;
> + atomic_set(&map->map_refs, 1);
> + list_add(&map->next, &info->mappings);
> + vma->vm_ops = &xenfb_vm_ops;
> + vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
> + vma->vm_private_data = map;
> + ret = 0;
> +
> + out:
> + up(&info->mm_lock);
> + return ret;
> +}
> +
> +static struct fb_ops xenfb_fb_ops = {
> + .owner = THIS_MODULE,
> + .fb_setcolreg = xenfb_setcolreg,
> + .fb_fillrect = xenfb_fillrect,
> + .fb_copyarea = xenfb_copyarea,
> + .fb_imageblit = xenfb_imageblit,
> + .fb_mmap = xenfb_mmap,
> +};
> +
> +static irqreturn_t xenfb_event_handler(int rq, void *dev_id,
> + struct pt_regs *regs)
> +{
> + struct xenfb_info *info = dev_id;
> + __u32 cons, prod;
> +
> + if (!info->page || !info->page->initialized)
> + return IRQ_NONE;
> +
> + /* FIXME barriers */
> + prod = XENFB_MASK_RING(info->page->in_prod, info->page->in);
> + cons = XENFB_MASK_RING(info->page->in_cons, info->page->in);
> +
> + if (prod == cons)
> + return IRQ_HANDLED;
> +
> + for (; cons!=prod; cons = XENFB_MASK_RING(cons+1, info->page->in)) {
> + union xenfb_in_event *event;
> + event = &info->page->in[cons];
> + notify_remote_via_evtchn(info->evtchn);
> + }
> +
> + info->page->in_cons = cons;
> +
> + return IRQ_HANDLED;
> +}
> +
> +static unsigned long vmalloc_to_mfn(void *address)
> +{
> + return pfn_to_mfn(vmalloc_to_pfn(address));
> +}
> +
> +static struct xenfb_info *xenfb_info;
> +static int xenfb_irq;
> +
> +static int __init xenfb_probe(void)
> +{
> + struct xenfb_info *info;
> + int i, ret;
> + struct fb_info *fb_info;
> + struct evtchn_alloc_unbound alloc_unbound;
> + xenbus_transaction_t xbt;
> +
> + info = kmalloc(sizeof(*info), GFP_KERNEL);
> + if (info == NULL)
> + return -ENOMEM;
> + memset(info, 0, sizeof(*info));
> +
> + INIT_LIST_HEAD(&info->mappings);
> +
> + info->fb = vmalloc(xenfb_mem_len);
> + if (info->fb == NULL)
> + goto error;
> + memset(info->fb, 0, xenfb_mem_len);
> + info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
> + info->pages = kmalloc(sizeof(struct page*)*info->nr_pages, GFP_KERNEL);
> + if (info->pages == NULL)
> + goto error_vfree;
> + for (i = 0; i < info->nr_pages; i++)
> + info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
> +
> + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
> + if (fb_info == NULL)
> + goto error_kfree;
> +
> + info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
> + /* set up shared page */
> + info->page = (void *)__get_free_page(GFP_KERNEL);
> + if (!info->page)
> + goto error_kfree;
> + /* set up event channel */
> + alloc_unbound.dom = DOMID_SELF;
> + alloc_unbound.remote_dom = 0;
> + ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
> + &alloc_unbound);
> + if (ret)
> + goto error_freep;
> + info->evtchn = alloc_unbound.port;
> +
> + for (i = 0; i < info->nr_pages; i++)
> + info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
> + info->page->pd[0] = vmalloc_to_mfn(info->mfns);
> + info->page->width = 800;
> + info->page->height = 600;
> + info->page->depth = 32; // FIXME was 24;
> + info->page->line_length = (info->page->depth / 8) * info->page->width;
> + info->page->mem_length = xenfb_mem_len;
> +
> + ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
> + 0, "xenfb", info);
> + if (ret < 0)
> + // FIXME need to close evtchn?
> + goto error_kfree;
> +
> + xenfb_irq = ret;
> + xenfb_info = info;
> +
> + fb_info->pseudo_palette = fb_info->par;
> + fb_info->par = info;
> + fb_info->screen_base = info->fb;
> +
> + memset(&fb_info->var, 0, sizeof(fb_info->var));
> + memset(&fb_info->fix, 0, sizeof(fb_info->fix));
> +
> + fb_info->fbops = &xenfb_fb_ops;
> + fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
> + fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
> + fb_info->var.bits_per_pixel = info->page->depth;
> +
> + fb_info->var.red = (struct fb_bitfield){16, 8, 0};
> + fb_info->var.green = (struct fb_bitfield){8, 8, 0};
> + fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
> +
> + fb_info->var.activate = FB_ACTIVATE_NOW;
> + fb_info->var.height = -1;
> + fb_info->var.width = -1;
> + fb_info->var.vmode = FB_VMODE_NONINTERLACED;
> +
> + fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
> + fb_info->fix.line_length = info->page->line_length;
> + fb_info->fix.smem_start = 0;
> + fb_info->fix.smem_len = xenfb_mem_len;
> + strcpy(fb_info->fix.id, "xen");
> + fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
> + fb_info->fix.accel = FB_ACCEL_NONE;
> +
> + fb_info->flags = FBINFO_FLAG_DEFAULT;
> +
> + fb_alloc_cmap(&fb_info->cmap, 256, 0);
> +
> + info->fb_info = fb_info;
> + info->fix = &fb_info->fix;
> + info->var = &fb_info->var;
> +
> + init_MUTEX(&info->mm_lock);
> + init_waitqueue_head(&info->wq);
> + init_timer(&info->refresh);
> + info->refresh.function = xenfb_timer;
> + info->refresh.data = (unsigned long)info;
> +
> + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
> +
> + ret = register_framebuffer(fb_info);
> + if (ret)
> + goto error_unbind;
> +
> + ret = xenbus_transaction_start(&xbt);
> + if (ret)
> + goto error_unreg;
> + ret = xenbus_printf(xbt, "vfb", "page-ref", "%lu",
> + virt_to_mfn(info->page));
> + if (ret)
> + goto error_xenbus;
> + ret = xenbus_printf(xbt, "vfb", "event-channel", "%u",
> + info->evtchn);
> + if (ret)
> + goto error_xenbus;
> + ret = xenbus_transaction_end(xbt, 0);
> + if (ret)
> + goto error_unreg;
> +
> + info->page->initialized = 1; /* FIXME needed? move up? */
> +
> + return 0;
> +
> + error_xenbus:
> + xenbus_transaction_end(xbt, 1);
> + error_unreg:
> + unregister_framebuffer(fb_info);
> + error_unbind:
> + unbind_from_irqhandler(xenfb_irq, info);
> + xenfb_irq = 0;
> + error_freep:
> + free_page((unsigned long)info->page);
> + error_kfree:
> + kfree(info->pages);
> + error_vfree:
> + vfree(info->fb);
> + error:
> + kfree(info);
> + xenfb_info = NULL;
> +
> + return -ENODEV;
> +}
> +
> +void xenfb_resume(void)
> +{
> +#if 0 /* FIXME */
> + int i, ret;
> +
> +#if 0
> + xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn);
> +#endif
> + for (i = 0; i < xenfb_info->nr_pages; i++)
> + xenfb_info->mfns[i] = vmalloc_to_mfn(xenfb_info->fb + i *
> PAGE_SIZE);
> + xenfb_info->page->pd[0] = vmalloc_to_mfn(xenfb_info->mfns);
> +
> +#if 0
> + if (xenfb_irq)
> + unbind_from_irqhandler(xenfb_irq, NULL);
> +#endif
> +
> +#if 0
> + printk("xenfb: resume(%d)\n", xen_start_info->fbdev_evtchn);
> + ret = bind_evtchn_to_irqhandler(xen_start_info->fbdev_evtchn,
> + xenfb_event_handler, 0, "xenfb",
> xenfb_info);
> +#endif
> + if (ret <= 0)
> + return;
> + xenfb_irq = ret;
> +#else
> + printk(KERN_DEBUG "xenfb_resume not implemented\n");
> +#endif
> +}
> +
> +static int __init xenfb_init(void)
> +{
> + return xenfb_probe();
> +}
> +
> +static void __exit xenfb_cleanup(void)
> +{
> + struct xenfb_info *info = xenfb_info;
> +
> + unregister_framebuffer(info->fb_info);
> + unbind_from_irqhandler(xenfb_irq, info);
> + xenfb_irq = 0;
> + free_page((unsigned long)info->page);
> + kfree(info->pages);
> + vfree(info->fb);
> + kfree(info);
> + xenfb_info = NULL;
> +}
> +
> +module_init(xenfb_init);
> +module_exit(xenfb_cleanup);
> +
> +MODULE_LICENSE("GPL");
> diff -r d8434a6fdd05 drivers/xen/xenkbd/Makefile
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/drivers/xen/xenkbd/Makefile Fri Jun 23 10:07:51 2006 +0200
> @@ -0,0 +1,1 @@
> +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o
> diff -r d8434a6fdd05 drivers/xen/xenkbd/xenkbd.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/drivers/xen/xenkbd/xenkbd.c Fri Jun 23 10:07:51 2006 +0200
> @@ -0,0 +1,206 @@
> +/*
> + * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
> + *
> + * Copyright (C) 2005
> + *
> + * Anthony Liguori <aliguori@xxxxxxxxxx>
> + *
> + * Based on linux/drivers/input/mouse/sermouse.c
> + *
> + * This file is subject to the terms and conditions of the GNU General
> Public
> + * License. See the file COPYING in the main directory of this archive for
> + * more details.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/input.h>
> +#include <asm/hypervisor.h>
> +#include <xen/evtchn.h>
> +#include <xen/xenbus.h>
> +#include <linux/xenkbd.h>
> +
> +struct xenkbd_device
> +{
> + struct input_dev *dev;
> + struct xenkbd_info *info;
> + unsigned evtchn;
> +};
> +
> +static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
> +{
> + struct xenkbd_device *dev = dev_id;
> + struct xenkbd_info *info = dev ? dev->info : 0;
> + static int button_map[3] = { BTN_RIGHT, BTN_MIDDLE, BTN_LEFT };
> + __u32 cons, prod;
> +
> + if (!info || !info->initialized)
> + return IRQ_NONE;
> +
> + /* FIXME barriers */
> + prod = XENKBD_MASK_RING(info->in_prod, info->in);
> + cons = XENKBD_MASK_RING(info->in_cons, info->in);
> +
> + if (prod == cons)
> + return IRQ_HANDLED;
> +
> + for (; cons != prod; cons = XENKBD_MASK_RING(cons + 1, info->in)) {
> + union xenkbd_in_event *event;
> +
> + event = &info->in[cons];
> +
> + switch (event->type) {
> + case XENKBD_TYPE_MOTION:
> + input_report_rel(dev->dev, REL_X, event->motion.rel_x);
> + input_report_rel(dev->dev, REL_Y, event->motion.rel_y);
> + break;
> + case XENKBD_TYPE_BUTTON:
> + if (event->button.button < 3)
> + input_report_key(dev->dev,
> +
> button_map[event->button.button],
> + event->button.pressed);
> + break;
> + case XENKBD_TYPE_KEY:
> + input_report_key(dev->dev, event->key.keycode,
> event->key.pressed);
> + break;
> + }
> +
> + notify_remote_via_evtchn(dev->evtchn);
> + }
> + input_sync(dev->dev);
> +
> + info->in_cons = cons;
> +
> + return IRQ_HANDLED;
> +}
> +
> +static struct xenkbd_device *xenkbd_dev;
> +static int xenkbd_irq;
> +
> +int __init xenkbd_init(void)
> +{
> + int ret = 0;
> + int i;
> + struct xenkbd_device *dev;
> + struct input_dev *input_dev;
> + struct evtchn_alloc_unbound alloc_unbound;
> + xenbus_transaction_t xbt;
> +
> + dev = kmalloc(sizeof(*dev), GFP_KERNEL);
> + input_dev = input_allocate_device();
> + if (!dev || !input_dev)
> + return -ENOMEM;
> +
> + dev->dev = input_dev;
> + dev->info = (void *)__get_free_page(GFP_KERNEL);
> + if (!dev->info) {
> + ret = -ENOMEM;
> + goto error;
> + }
> + dev->info->initialized = 0;
> +
> + alloc_unbound.dom = DOMID_SELF;
> + alloc_unbound.remote_dom = 0;
> + ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
> + &alloc_unbound);
> + if (ret)
> + goto error_freep;
> + dev->evtchn = alloc_unbound.port;
> + ret = bind_evtchn_to_irqhandler(dev->evtchn, input_handler, 0,
> + "xenkbd", dev);
> + if (ret < 0)
> + goto error_freep;
> +
> + xenkbd_irq = ret;
> +
> + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
> + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
> + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
> +
> + /* FIXME */
> + for (i = 0; i < 256; i++)
> + set_bit(i, input_dev->keybit);
> +
> + input_dev->name = "Xen Virtual Keyboard/Mouse";
> +
> + input_register_device(input_dev);
> +
> + ret = xenbus_transaction_start(&xbt);
> + if (ret)
> + goto error_unreg;
> + ret = xenbus_printf(xbt, "vkbd", "page-ref", "%lu",
> + virt_to_mfn(dev->info));
> + if (ret)
> + goto error_xenbus;
> + ret = xenbus_printf(xbt, "vkbd", "event-channel", "%u",
> + dev->evtchn);
> + if (ret)
> + goto error_xenbus;
> + ret = xenbus_transaction_end(xbt, 0);
> + if (ret)
> + goto error_unreg;
> +
> + dev->info->in_cons = dev->info->in_prod = 0;
> + dev->info->out_cons = dev->info->out_prod = 0;
> + dev->info->initialized = 1; /* FIXME needed? move up? */
> +
> + xenkbd_dev = dev;
> +
> + return ret;
> +
> +
> + error_xenbus:
> + xenbus_transaction_end(xbt, 1);
> + error_unreg:
> + input_unregister_device(input_dev);
> + unbind_from_irqhandler(xenkbd_irq, dev);
> + xenkbd_irq = 0;
> + error_freep:
> + free_page((unsigned long)dev->info);
> + error:
> + kfree(dev);
> + xenkbd_dev = NULL;
> + return ret;
> +}
> +
> +static void __exit xenkbd_cleanup(void)
> +{
> + input_unregister_device(xenkbd_dev->dev);
> + unbind_from_irqhandler(xenkbd_irq, xenkbd_dev);
> + xenkbd_irq = 0;
> + free_page((unsigned long)xenkbd_dev->info);
> + kfree(xenkbd_dev);
> + xenkbd_dev = NULL;
> +}
> +
> +void xenkbd_resume(void)
> +{
> +#if 0
> + int ret;
> +
> + if (xenkbd_dev && xen_start_info->kbd_evtchn) {
> + if (xenkbd_irq)
> + unbind_from_irqhandler(xenkbd_irq, NULL);
> +
> + ret = bind_evtchn_to_irqhandler(xen_start_info->kbd_evtchn,
> + input_handler,
> + 0,
> + "xenkbd",
> + xenkbd_dev);
> +
> + if (ret <= 0)
> + return;
> +
> + xenkbd_irq = ret;
> + xenkbd_dev->info = mfn_to_virt(xen_start_info->kbd_mfn);
> + }
> +#else
> + printk(KERN_DEBUG "xenkbd_resume not implemented\n");
> +#endif
> +}
> +
> +module_init(xenkbd_init);
> +module_exit(xenkbd_cleanup);
> +
> +MODULE_LICENSE("GPL");
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxx
> http://lists.xensource.com/xen-devel
>
>
--
Laurent Vivier
Bull, Architect of an Open World (TM)
http://www.bullopensource.org/ext4
signature.asc
Description: OpenPGP digital signature
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|