^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Xen para-virtual frame buffer device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on linux/drivers/video/q40fb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Switch to grant tables when they become capable of dealing with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * frame buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/xen/hypervisor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <xen/xen.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <xen/events.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <xen/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <xen/interface/io/fbif.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <xen/interface/io/protocols.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <xen/xenbus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <xen/platform_pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct xenfb_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned char *fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct fb_info *fb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int x1, y1, x2, y2; /* dirty rectangle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) protected by dirty_lock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) spinlock_t dirty_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int nr_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct xenfb_page *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned long *gfns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int update_wanted; /* XENFB_TYPE_UPDATE wanted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int feature_resize; /* XENFB_TYPE_RESIZE ok */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct xenfb_resize resize; /* protected by resize_lock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int resize_dpy; /* ditto */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) spinlock_t resize_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct xenbus_device *xbdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) enum { KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int video[KPARAM_CNT] = { 2, XENFB_WIDTH, XENFB_HEIGHT };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) module_param_array(video, int, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) MODULE_PARM_DESC(video,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) "Video memory size in MB, width, height in pixels (default 2,800,600)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static void xenfb_make_preferred_console(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int xenfb_remove(struct xenbus_device *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static void xenfb_disconnect_backend(struct xenfb_info *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static void xenfb_send_event(struct xenfb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) union xenfb_out_event *event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u32 prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) prod = info->page->out_prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* caller ensures !xenfb_queue_full() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) mb(); /* ensure ring space available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) XENFB_OUT_RING_REF(info->page, prod) = *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) wmb(); /* ensure ring contents visible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) info->page->out_prod = prod + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) notify_remote_via_irq(info->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static void xenfb_do_update(struct xenfb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int x, int y, int w, int h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) union xenfb_out_event event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) memset(&event, 0, sizeof(event));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) event.type = XENFB_TYPE_UPDATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) event.update.x = x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) event.update.y = y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) event.update.width = w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) event.update.height = h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* caller ensures !xenfb_queue_full() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) xenfb_send_event(info, &event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static void xenfb_do_resize(struct xenfb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) union xenfb_out_event event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) memset(&event, 0, sizeof(event));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) event.resize = info->resize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* caller ensures !xenfb_queue_full() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) xenfb_send_event(info, &event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static int xenfb_queue_full(struct xenfb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) u32 cons, prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) prod = info->page->out_prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) cons = info->page->out_cons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return prod - cons == XENFB_OUT_RING_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) static void xenfb_handle_resize_dpy(struct xenfb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) spin_lock_irqsave(&info->resize_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (info->resize_dpy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (!xenfb_queue_full(info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) info->resize_dpy = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) xenfb_do_resize(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) spin_unlock_irqrestore(&info->resize_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static void xenfb_refresh(struct xenfb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) int x1, int y1, int w, int h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) int x2 = x1 + w - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int y2 = y1 + h - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) xenfb_handle_resize_dpy(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (!info->update_wanted)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) spin_lock_irqsave(&info->dirty_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* Combine with dirty rectangle: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (info->y1 < y1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) y1 = info->y1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (info->y2 > y2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) y2 = info->y2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (info->x1 < x1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) x1 = info->x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (info->x2 > x2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) x2 = info->x2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (xenfb_queue_full(info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* Can't send right now, stash it in the dirty rectangle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) info->x1 = x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) info->x2 = x2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) info->y1 = y1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) info->y2 = y2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) spin_unlock_irqrestore(&info->dirty_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* Clear dirty rectangle: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) info->x1 = info->y1 = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) info->x2 = info->y2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) spin_unlock_irqrestore(&info->dirty_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (x1 <= x2 && y1 <= y2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static void xenfb_deferred_io(struct fb_info *fb_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct list_head *pagelist)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct xenfb_info *info = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) struct page *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) unsigned long beg, end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) int y1, y2, miny, maxy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) miny = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) maxy = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) list_for_each_entry(page, pagelist, lru) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) beg = page->index << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) end = beg + PAGE_SIZE - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) y1 = beg / fb_info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) y2 = end / fb_info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (y2 >= fb_info->var.yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) y2 = fb_info->var.yres - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (miny > y1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) miny = y1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (maxy < y2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) maxy = y2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static struct fb_deferred_io xenfb_defio = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) .delay = HZ / 20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) .deferred_io = xenfb_deferred_io,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) unsigned blue, unsigned transp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (regno > info->cmap.len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) red = CNVT_TOHW(red, info->var.red.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) green = CNVT_TOHW(green, info->var.green.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) blue = CNVT_TOHW(blue, info->var.blue.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) transp = CNVT_TOHW(transp, info->var.transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) #undef CNVT_TOHW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) v = (red << info->var.red.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) (green << info->var.green.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) (blue << info->var.blue.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) ((u32 *)info->pseudo_palette)[regno] = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) struct xenfb_info *info = p->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) sys_fillrect(p, rect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct xenfb_info *info = p->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) sys_imageblit(p, image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct xenfb_info *info = p->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) sys_copyarea(p, area);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static ssize_t xenfb_write(struct fb_info *p, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct xenfb_info *info = p->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) ssize_t res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) res = fb_sys_write(p, buf, count, ppos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) xenfb_refresh(info, 0, 0, info->page->width, info->page->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) struct xenfb_info *xenfb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) int required_mem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) xenfb_info = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (!xenfb_info->feature_resize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (var->xres == video[KPARAM_WIDTH] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) var->yres == video[KPARAM_HEIGHT] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) var->bits_per_pixel == xenfb_info->page->depth) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /* Can't resize past initial width and height */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) required_mem_len = var->xres * var->yres * xenfb_info->page->depth / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (var->bits_per_pixel == xenfb_info->page->depth &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) required_mem_len <= info->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) var->xres_virtual = var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) var->yres_virtual = var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static int xenfb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct xenfb_info *xenfb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) xenfb_info = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) spin_lock_irqsave(&xenfb_info->resize_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) xenfb_info->resize.type = XENFB_TYPE_RESIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) xenfb_info->resize.width = info->var.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) xenfb_info->resize.height = info->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) xenfb_info->resize.stride = info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) xenfb_info->resize.depth = info->var.bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) xenfb_info->resize.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) xenfb_info->resize_dpy = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) spin_unlock_irqrestore(&xenfb_info->resize_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static const struct fb_ops xenfb_fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) .fb_read = fb_sys_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .fb_write = xenfb_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) .fb_setcolreg = xenfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) .fb_fillrect = xenfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) .fb_copyarea = xenfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) .fb_imageblit = xenfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) .fb_check_var = xenfb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .fb_set_par = xenfb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static irqreturn_t xenfb_event_handler(int rq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * No in events recognized, simply ignore them all.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * If you need to recognize some, see xen-kbdfront's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * input_handler() for how to do that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct xenfb_info *info = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct xenfb_page *page = info->page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (page->in_cons != page->in_prod) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) info->page->in_cons = info->page->in_prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) notify_remote_via_irq(info->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /* Flush dirty rectangle: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static int xenfb_probe(struct xenbus_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) const struct xenbus_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) struct xenfb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct fb_info *fb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) int fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) info = kzalloc(sizeof(*info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (info == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /* Limit kernel param videoram amount to what is in xenstore */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (val < video[KPARAM_MEM])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) video[KPARAM_MEM] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) video[KPARAM_WIDTH] = xenbus_read_unsigned(dev->otherend, "width",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) video[KPARAM_WIDTH]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) video[KPARAM_HEIGHT] = xenbus_read_unsigned(dev->otherend, "height",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) video[KPARAM_HEIGHT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /* If requested res does not fit in available memory, use default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) fb_size = video[KPARAM_MEM] * 1024 * 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH / 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) > fb_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) pr_warn("display parameters %d,%d,%d invalid, use defaults\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) video[KPARAM_MEM], video[KPARAM_WIDTH],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) video[KPARAM_HEIGHT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) video[KPARAM_WIDTH] = XENFB_WIDTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) video[KPARAM_HEIGHT] = XENFB_HEIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) fb_size = XENFB_DEFAULT_FB_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) dev_set_drvdata(&dev->dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) info->xbdev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) info->irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) info->x1 = info->y1 = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) spin_lock_init(&info->dirty_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) spin_lock_init(&info->resize_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) info->fb = vzalloc(fb_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (info->fb == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) goto error_nomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) info->gfns = vmalloc(array_size(sizeof(unsigned long), info->nr_pages));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (!info->gfns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) goto error_nomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) /* set up shared page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (!info->page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) goto error_nomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) /* abusing framebuffer_alloc() to allocate pseudo_palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (fb_info == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) goto error_nomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) /* complete the abuse: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) fb_info->pseudo_palette = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) fb_info->par = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) fb_info->screen_base = info->fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) fb_info->fbops = &xenfb_fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) fb_info->var.bits_per_pixel = XENFB_DEPTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) fb_info->var.red = (struct fb_bitfield){16, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) fb_info->var.green = (struct fb_bitfield){8, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) fb_info->var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) fb_info->var.height = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) fb_info->var.width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) fb_info->var.vmode = FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) fb_info->fix.line_length = fb_info->var.xres * XENFB_DEPTH / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) fb_info->fix.smem_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) fb_info->fix.smem_len = fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) strcpy(fb_info->fix.id, "xen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) fb_info->fix.accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) framebuffer_release(fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) xenbus_dev_fatal(dev, ret, "fb_alloc_cmap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) fb_info->fbdefio = &xenfb_defio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) fb_deferred_io_init(fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) xenfb_init_shared_page(info, fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) ret = xenfb_connect_backend(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) xenbus_dev_fatal(dev, ret, "xenfb_connect_backend");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) goto error_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) ret = register_framebuffer(fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) xenbus_dev_fatal(dev, ret, "register_framebuffer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) goto error_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) info->fb_info = fb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) xenfb_make_preferred_console();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) error_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) fb_deferred_io_cleanup(fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) fb_dealloc_cmap(&fb_info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) framebuffer_release(fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) error_nomem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) xenbus_dev_fatal(dev, ret, "allocating device memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) xenfb_remove(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static void xenfb_make_preferred_console(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) struct console *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (console_set_on_cmdline)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) for_each_console(c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (!strcmp(c->name, "tty") && c->index == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) unregister_console(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) c->flags |= CON_CONSDEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) c->flags &= ~CON_PRINTBUFFER; /* don't print again */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) register_console(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) static int xenfb_resume(struct xenbus_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) struct xenfb_info *info = dev_get_drvdata(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) xenfb_disconnect_backend(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) xenfb_init_shared_page(info, info->fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return xenfb_connect_backend(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static int xenfb_remove(struct xenbus_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) struct xenfb_info *info = dev_get_drvdata(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) xenfb_disconnect_backend(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (info->fb_info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) fb_deferred_io_cleanup(info->fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) unregister_framebuffer(info->fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) fb_dealloc_cmap(&info->fb_info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) framebuffer_release(info->fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) free_page((unsigned long)info->page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) vfree(info->gfns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) vfree(info->fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static unsigned long vmalloc_to_gfn(void *address)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return xen_page_to_gfn(vmalloc_to_page(address));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) static void xenfb_init_shared_page(struct xenfb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) struct fb_info *fb_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) int epd = PAGE_SIZE / sizeof(info->gfns[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) for (i = 0; i < info->nr_pages; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) info->gfns[i] = vmalloc_to_gfn(info->fb + i * PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) for (i = 0; i * epd < info->nr_pages; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) info->page->pd[i] = vmalloc_to_gfn(&info->gfns[i * epd]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) info->page->width = fb_info->var.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) info->page->height = fb_info->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) info->page->depth = fb_info->var.bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) info->page->line_length = fb_info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) info->page->mem_length = fb_info->fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) info->page->in_cons = info->page->in_prod = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) info->page->out_cons = info->page->out_prod = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) static int xenfb_connect_backend(struct xenbus_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) struct xenfb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) int ret, evtchn, irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) struct xenbus_transaction xbt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) ret = xenbus_alloc_evtchn(dev, &evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 0, dev->devicetype, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (irq < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) xenbus_free_evtchn(dev, evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) again:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) ret = xenbus_transaction_start(&xbt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) xenbus_dev_fatal(dev, ret, "starting transaction");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) goto unbind_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) virt_to_gfn(info->page));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) goto error_xenbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) goto error_xenbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) XEN_IO_PROTO_ABI_NATIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) goto error_xenbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) goto error_xenbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) ret = xenbus_transaction_end(xbt, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (ret == -EAGAIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) goto again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) xenbus_dev_fatal(dev, ret, "completing transaction");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) goto unbind_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) xenbus_switch_state(dev, XenbusStateInitialised);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) info->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) error_xenbus:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) xenbus_transaction_end(xbt, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) xenbus_dev_fatal(dev, ret, "writing xenstore");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) unbind_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) unbind_from_irqhandler(irq, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) static void xenfb_disconnect_backend(struct xenfb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) /* Prevent xenfb refresh */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) info->update_wanted = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) if (info->irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) unbind_from_irqhandler(info->irq, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) info->irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) static void xenfb_backend_changed(struct xenbus_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) enum xenbus_state backend_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) struct xenfb_info *info = dev_get_drvdata(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) switch (backend_state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) case XenbusStateInitialising:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) case XenbusStateInitialised:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) case XenbusStateReconfiguring:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) case XenbusStateReconfigured:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) case XenbusStateUnknown:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) case XenbusStateInitWait:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) xenbus_switch_state(dev, XenbusStateConnected);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) case XenbusStateConnected:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * Work around xenbus race condition: If backend goes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * through InitWait to Connected fast enough, we can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) * get Connected twice here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) if (dev->state != XenbusStateConnected)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) /* no InitWait seen yet, fudge it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) xenbus_switch_state(dev, XenbusStateConnected);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) if (xenbus_read_unsigned(info->xbdev->otherend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) "request-update", 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) info->update_wanted = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) info->feature_resize = xenbus_read_unsigned(dev->otherend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) "feature-resize", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) case XenbusStateClosed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (dev->state == XenbusStateClosed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) fallthrough; /* Missed the backend's CLOSING state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) case XenbusStateClosing:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) xenbus_frontend_closed(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) static const struct xenbus_device_id xenfb_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) { "vfb" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) { "" }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) static struct xenbus_driver xenfb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) .ids = xenfb_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) .probe = xenfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) .remove = xenfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) .resume = xenfb_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) .otherend_changed = xenfb_backend_changed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) static int __init xenfb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (!xen_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) /* Nothing to do if running in dom0. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) if (xen_initial_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (!xen_has_pv_devices())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return xenbus_register_frontend(&xenfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static void __exit xenfb_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) xenbus_unregister_driver(&xenfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) module_init(xenfb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) module_exit(xenfb_cleanup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) MODULE_DESCRIPTION("Xen virtual framebuffer device frontend");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) MODULE_ALIAS("xen:vfb");