[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend



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

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.