This takes an existing configured pipe/plane and allocates a new frame
buffer for it, then it hooks that up to the framebuffer driver to create an
fb device. Suitable hacks to the X server to leave the vt in KD_TEXT mode
and you can use this fb device with fbcon to show console messages while X
is up and running.

Signed-off-by: Keith Packard <[EMAIL PROTECTED]>
---
 drivers/gpu/drm/Kconfig              |    3 +
 drivers/gpu/drm/i915/Makefile        |    3 +-
 drivers/gpu/drm/i915/i915_debug_fb.c |  435 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_debug_fb.h |   14 +
 drivers/gpu/drm/i915/i915_drv.h      |    7 +
 drivers/gpu/drm/i915/i915_gem.c      |    2 +
 drivers/gpu/drm/i915/i915_gem_proc.c |  106 ++++++++
 7 files changed, 569 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/i915_debug_fb.c
 create mode 100644 drivers/gpu/drm/i915/i915_debug_fb.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index a8b33c2..9612ee0 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -66,6 +66,9 @@ config DRM_I830
 
 config DRM_I915
        tristate "i915 driver"
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          Choose this option if you have a system that has Intel 830M, 845G,
          852GM, 855GM 865G or 915G integrated graphics.  If M is selected, the
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index d8fb5d8..9a83df3 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -8,7 +8,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
          i915_gem.o \
          i915_gem_debug.o \
          i915_gem_proc.o \
-         i915_gem_tiling.o
+         i915_gem_tiling.o \
+         i915_debug_fb.o
 
 i915-$(CONFIG_ACPI)    += i915_opregion.o
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
diff --git a/drivers/gpu/drm/i915/i915_debug_fb.c 
b/drivers/gpu/drm/i915/i915_debug_fb.c
new file mode 100644
index 0000000..02919b7
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_debug_fb.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright © 2008 Keith Packard <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+/*
+ * Debug frame buffer. This steals one of the video outputs
+ * and replaces the frame buffer with our own memory
+ */
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tc.h>
+#include <linux/types.h>
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "i915_reg.h"
+#include <linux/swap.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+struct debug_fb_par {
+       int pipe;
+       int gtt_base;
+       size_t size;
+       struct drm_gem_object *fb_object;
+       u32 pseudo_palette[16];
+       u32 dspaddr_reg;
+       u32 saveDSPADDR;
+       u32 dspsurf_reg;
+       u32 saveDSPSURF;
+       u32 dsptileoff_reg;
+       u32 saveDSPTILEOFF;
+};
+
+static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
+{
+       unsigned int mask = (1 << bf->length) - 1;
+
+       return (val >> (16 - bf->length) & mask) << bf->offset;
+}
+
+static int i915_debug_fb_setcolreg(u_int regno, u_int red, u_int green, u_int 
blue,
+                                  u_int transp, struct fb_info *info)
+{
+       u32 v;
+
+       /* 16 registers */
+       if (regno >= 16)
+               return 1;
+
+       v = (convert_bitfield(transp, &info->var.transp) |
+            convert_bitfield(blue, &info->var.blue) |
+            convert_bitfield(green, &info->var.green) |
+            convert_bitfield(red, &info->var.red));
+
+       printk(KERN_INFO "color register %d rgb %04x %04x %04x v %08x\n",
+              regno, red, green, blue, v);
+
+       ((u32 *) (info->pseudo_palette))[regno] = v;
+       return 0;
+}
+
+static struct fb_var_screeninfo debug_fb_var = {
+       .xres           = 1024,
+       .yres           = 768,
+       .xres_virtual   = 1024,
+       .yres_virtual   = 768,
+       .bits_per_pixel = 32,
+       .red.length     = 8,
+       .green.length   = 8,
+       .blue.length    = 8,
+       .activate       = FB_ACTIVATE_NOW,
+       .height         = -1,
+       .width          = -1,
+       .accel_flags    = FB_ACCEL_NONE,
+       .pixclock       = 14452,
+       .left_margin    = 116,
+       .right_margin   = 12,
+       .upper_margin   = 34,
+       .lower_margin   = 12,
+       .hsync_len      = 128,
+       .vsync_len      = 3,
+       .sync           = FB_SYNC_ON_GREEN,
+       .vmode          = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo debug_fb_fix = {
+       .id             = "DEBUG-FB",
+       .type           = FB_TYPE_PACKED_PIXELS,
+       .visual         = FB_VISUAL_TRUECOLOR,
+};
+
+static void i915_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+#if 0
+       printk(KERN_INFO "imageblit state %d visual %d x %d y %d depth %d\n",
+              p->state, p->fix.visual, image->dx, image->dy, image->depth);
+       printk(KERN_INFO " fg %d -> %08x bg %d -> %08x\n",
+              image->fg_color,
+              ((u32*)(p->pseudo_palette))[image->fg_color],
+              image->bg_color,
+              ((u32*)(p->pseudo_palette))[image->bg_color]);
+#endif
+       cfb_imageblit(p, image);
+}
+
+static struct fb_ops debug_fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_setcolreg   = i915_debug_fb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = i915_imageblit,
+};
+
+static int pipe_for_plane(struct drm_device *dev, int plane)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 dspcntr_reg = plane == 0 ? DSPACNTR : DSPBCNTR;
+       u32 dspcntr;
+
+       dspcntr = I915_READ(dspcntr_reg);
+       if (!(dspcntr & DISPLAY_PLANE_ENABLE))
+               return -1;
+
+       switch (dspcntr & DISPPLANE_SEL_PIPE_MASK) {
+       case DISPPLANE_SEL_PIPE_A:
+               return 0;
+       case DISPPLANE_SEL_PIPE_B:
+               return 1;
+       default:
+               return -1;
+       }
+}
+
+static int plane_for_pipe(struct drm_device *dev, int pipe)
+{
+       if (pipe_for_plane(dev, 0) == pipe)
+               return 0;
+       if (pipe_for_plane(dev, 1) == pipe)
+               return 1;
+       return -1;
+}
+
+int i915_debug_fb_create(struct drm_device *dev, int pipe)
+{
+       struct drm_minor *minor = dev->primary;
+       struct device *device = &minor->kdev;
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct fb_info *info;
+       struct debug_fb_par *par;
+       int err;
+       int plane;
+       int width, height, bpp, depth, stride;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       u32 dspcntr_reg, dspsize_reg, dspstride_reg, dspaddr_reg, pipesrc_reg;
+       u32 dspcntr, dspsize, dspstride, dspaddr, pipesrc;
+       u32 dspsurf_reg, dspsurf = 0;
+       u32 dsptileoff_reg, dsptileoff = 0;
+
+       plane = plane_for_pipe(dev, pipe);
+
+       switch (pipe) {
+       case 0:
+               pipesrc_reg = PIPEASRC;
+               break;
+       case 1:
+               pipesrc_reg = PIPEBSRC;
+               break;
+       default:
+               printk(KERN_ERR "pipe %d is not running\n", pipe);
+               return -ENXIO;
+       }
+
+       switch (plane) {
+       case 0:
+               dspcntr_reg = DSPACNTR;
+               dspsize_reg = DSPASIZE;
+               dspstride_reg = DSPASTRIDE;
+               dspaddr_reg = DSPAADDR;
+               dspsurf_reg = DSPASURF;
+               dsptileoff_reg = DSPATILEOFF;
+               break;
+       case 1:
+               dspcntr_reg = DSPBCNTR;
+               dspsize_reg = DSPBSIZE;
+               dspstride_reg = DSPBSTRIDE;
+               dspaddr_reg = DSPBADDR;
+               dspsurf_reg = DSPBSURF;
+               dsptileoff_reg = DSPBTILEOFF;
+               break;
+       default:
+               printk(KERN_ERR "pipe %d is not running\n", pipe);
+               return -ENXIO;
+       }
+       pipesrc = I915_READ(pipesrc_reg);
+       dspcntr = I915_READ(dspcntr_reg);
+       dspsize = I915_READ(dspsize_reg);
+       dspstride = I915_READ(dspstride_reg);
+       dspaddr = I915_READ(dspaddr_reg);
+       if (IS_I965G(dev)) {
+               dspsurf = I915_READ(dspsurf_reg);
+               dsptileoff = I915_READ(dsptileoff_reg);
+       }
+
+       switch (dspcntr & DISPPLANE_PIXFORMAT_MASK) {
+       case DISPPLANE_8BPP:
+       default:
+               bpp = 8; depth = 8; break;
+       case DISPPLANE_15_16BPP:
+               bpp = 16; depth = 15; break;
+       case DISPPLANE_16BPP:
+               bpp = 16; depth = 16; break;
+       case DISPPLANE_32BPP_NO_ALPHA:
+       case DISPPLANE_32BPP:
+               bpp = 32; depth = 24; break;
+       }
+       width = ((pipesrc >> 16) & 0xffff) + 1;
+       height = (pipesrc & 0xffff) + 1;
+       stride = (dspstride / (bpp / 8));
+       printk(KERN_INFO "detected plane %dx%d stride %d bpp %d\n",
+              width, height, stride, bpp);
+
+       info = framebuffer_alloc(sizeof(struct debug_fb_par), device);
+       if (!info) {
+               printk(KERN_ERR "%s: Cannot allocate memory\n", device->bus_id);
+               return -ENOMEM;
+       }
+
+       par = info->par;
+
+       par->pipe = pipe;
+       par->size = height * stride * bpp / 8;
+       par->dspaddr_reg = dspaddr_reg;
+       par->saveDSPADDR = dspaddr;
+       par->dspsurf_reg = dspsurf_reg;
+       par->saveDSPSURF = dspsurf;
+       par->dsptileoff_reg = dsptileoff_reg;
+       par->saveDSPTILEOFF = dsptileoff;
+       printk(KERN_INFO "save: DSPADDR %08x DSPSURF %08x DSPTILEOFF %08x\n",
+              par->saveDSPADDR, par->saveDSPSURF, par->saveDSPTILEOFF);
+
+       par->fb_object = drm_gem_object_alloc(dev, par->size);
+       printk(KERN_INFO "created object %p\n", par->fb_object);
+
+       if (!par->fb_object) {
+               printk(KERN_ERR "%s: Cannot allocate memory\n", device->bus_id);
+               err = -ENOMEM;
+               goto err_alloc;
+       }
+       obj = par->fb_object;
+       obj_priv = obj->driver_private;
+
+       err = i915_gem_object_pin(obj, 128 * 1024);
+
+       i915_gem_clflush_object (obj);
+       drm_agp_chipset_flush(dev);
+       obj->write_domain = 0;
+
+       printk(KERN_INFO "pinning returns %d\n", err);
+
+       if (err) {
+               printk(KERN_ERR "%s: Cannot pin framebuffer\n", device->bus_id);
+               goto err_pin;
+       }
+
+       dev_priv->fb_info = info;
+
+       info->fbops = &debug_fb_ops;
+       info->fix = debug_fb_fix;
+       info->var = debug_fb_var;
+       info->pseudo_palette = par->pseudo_palette;
+
+       info->var.xres = info->var.xres_virtual = width;
+       info->var.yres = info->var.yres_virtual = height;
+       info->var.bits_per_pixel = bpp;
+       switch (depth) {
+       case 8:
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+       case 15:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               info->var.red.offset = 10;
+               info->var.red.length = 5;
+               info->var.green.offset = 5;
+               info->var.green.length = 5;
+               info->var.blue.offset = 0;
+               info->var.blue.length = 5;
+               break;
+       case 16:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               info->var.red.offset = 11;
+               info->var.red.length = 5;
+               info->var.green.offset = 5;
+               info->var.green.length = 6;
+               info->var.blue.offset = 0;
+               info->var.blue.length = 5;
+               break;
+       case 24:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               info->var.red.offset = 16;
+               info->var.red.length = 8;
+               info->var.green.offset = 8;
+               info->var.green.length = 8;
+               info->var.blue.offset = 0;
+               info->var.blue.length = 8;
+               break;
+       }
+
+       info->flags = FBINFO_DEFAULT;
+
+       /* Frame buffer mapping setup.  */
+       info->fix.smem_start = dev->agp->base + obj_priv->gtt_offset;
+       info->fix.smem_len = par->size;
+       info->fix.line_length = stride * bpp / 8;
+
+       printk(KERN_INFO "start %lx len %d\n", info->fix.smem_start, 
info->fix.smem_len);
+
+       info->screen_base = ioremap_wc(info->fix.smem_start,
+                                      info->fix.smem_len);
+       printk(KERN_INFO "screen mapped at %p\n", info->screen_base);
+       if (!info->screen_base) {
+               printk(KERN_ERR "%s: Cannot map FB\n", device->bus_id);
+               err = -ENOMEM;
+               goto err_ioremap;
+       }
+       info->screen_size = info->fix.smem_len;
+       memset(info->screen_base, 0, info->screen_size);
+
+       err = register_framebuffer(info);
+       if (err < 0) {
+               printk(KERN_ERR "%s: Cannot register framebuffer\n",
+                      device->bus_id);
+               goto err_register;
+       }
+
+       if (IS_I965G(dev)) {
+               I915_WRITE(dspaddr_reg, 0);
+               I915_WRITE(dspsurf_reg, obj_priv->gtt_offset);
+               I915_WRITE(dsptileoff_reg, 0);
+               (void) I915_READ(dspsurf_reg);
+       } else {
+               I915_WRITE(dspaddr_reg, obj_priv->gtt_offset);
+               (void) I915_READ(dspaddr_reg);
+       }
+
+       pr_info("fb%d: %s frame buffer device at %s\n",
+               info->node, info->fix.id, device->bus_id);
+
+       return 0;
+
+err_register:
+       iounmap(info->screen_base);
+err_ioremap:
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_object_unpin(obj);
+       mutex_unlock(&dev->struct_mutex);
+err_pin:
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+err_alloc:
+       framebuffer_release(info);
+       return err;
+}
+
+int i915_debug_fb_pipe(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct fb_info *info = dev_priv->fb_info;
+       struct debug_fb_par *par;
+
+       if (!info)
+               return -1;
+       par = info->par;
+       return par->pipe;
+}
+
+int i915_debug_fb_destroy(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct fb_info *info = dev_priv->fb_info;
+       struct debug_fb_par *par;
+       struct drm_gem_object *obj;
+
+       if (!info)
+               return 0;
+       par = info->par;
+       obj = par->fb_object;
+
+       printk(KERN_INFO "restore: DSPADDR %08x DSPSURF %08x DSPTILEOFF %08x\n",
+              par->saveDSPADDR, par->saveDSPSURF, par->saveDSPTILEOFF);
+       if (IS_I965G(dev)) {
+               I915_WRITE(par->dspaddr_reg, par->saveDSPADDR);
+               I915_WRITE(par->dspsurf_reg, par->saveDSPSURF);
+               I915_WRITE(par->dsptileoff_reg, par->saveDSPTILEOFF);
+               (void) I915_READ(par->dsptileoff_reg);
+       } else {
+               I915_WRITE(par->dspaddr_reg, par->saveDSPADDR);
+               (void) I915_READ(par->dspaddr_reg);
+       }
+
+       unregister_framebuffer(info);
+       iounmap(info->screen_base);
+
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_object_unpin(par->fb_object);
+       drm_gem_object_unreference(par->fb_object);
+       mutex_unlock(&dev->struct_mutex);
+
+       framebuffer_release(info);
+
+       dev_priv->fb_info = NULL;
+       return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_debug_fb.h 
b/drivers/gpu/drm/i915/i915_debug_fb.h
new file mode 100644
index 0000000..7269382
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_debug_fb.h
@@ -0,0 +1,14 @@
+
+/* IOmem resource offsets.  */
+#define PMAG_BA_FBMEM          0x000000        /* frame buffer */
+#define PMAG_BA_BT459          0x200000        /* Bt459 RAMDAC */
+#define PMAG_BA_IRQ            0x300000        /* IRQ acknowledge */
+#define PMAG_BA_ROM            0x380000        /* REX option ROM */
+#define PMAG_BA_BT438          0x380000        /* Bt438 clock chip reset */
+#define PMAG_BA_SIZE           0x400000        /* address space size */
+
+/* Bt459 register offsets, byte-wide registers.  */
+#define BT459_ADDR_LO          0x0             /* address low */
+#define BT459_ADDR_HI          0x4             /* address high */
+#define BT459_DATA             0x8             /* data window register */
+#define BT459_CMAP             0xc             /* color map window register */
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2dfd4ac..868aefd 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -152,6 +152,8 @@ typedef struct drm_i915_private {
 
        struct intel_opregion opregion;
 
+       struct fb_info *fb_info;
+
        /* Register state */
        u8 saveLBB;
        u32 saveDSPACNTR;
@@ -521,6 +523,11 @@ void i915_gem_retire_requests(struct drm_device *dev);
 void i915_gem_retire_work_handler(struct work_struct *work);
 void i915_gem_clflush_object(struct drm_gem_object *obj);
 
+/* i915_debug_fb.c */
+int i915_debug_fb_create(struct drm_device *dev, int pipe);
+int i915_debug_fb_pipe(struct drm_device *dev);
+int i915_debug_fb_destroy(struct drm_device *dev);
+
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 61f16e2..584195c 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2600,6 +2600,8 @@ i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
        ret = i915_gem_idle(dev);
        drm_irq_uninstall(dev);
 
+       i915_debug_fb_destroy(dev);
+
        io_mapping_free(dev_priv->mm.gtt_mapping);
        return ret;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_proc.c 
b/drivers/gpu/drm/i915/i915_gem_proc.c
index 93de15b..754b252 100644
--- a/drivers/gpu/drm/i915/i915_gem_proc.c
+++ b/drivers/gpu/drm/i915/i915_gem_proc.c
@@ -238,19 +238,96 @@ static int i915_interrupt_info(char *buf, char **start, 
off_t offset,
        if (dev_priv->hw_status_page != NULL) {
                DRM_PROC_PRINT("Current sequence:    %d\n",
                               i915_get_gem_seqno(dev));
+               DRM_PROC_PRINT("Current breadcrumb:  %d\n",
+                              READ_BREADCRUMB(dev_priv));
        } else {
                DRM_PROC_PRINT("Current sequence:    hws uninitialized\n");
+               DRM_PROC_PRINT("Current breadcrumb:  hws uninitialized\n");
        }
        DRM_PROC_PRINT("Waiter sequence:     %d\n",
                       dev_priv->mm.waiting_gem_seqno);
+       DRM_PROC_PRINT("Waiter breadcrumb:   %d\n",
+                      dev_priv->breadcrumb_wait);
        DRM_PROC_PRINT("IRQ sequence:        %d\n",
                       dev_priv->mm.irq_gem_seqno);
+       if (dev_priv->sarea_priv) {
+               DRM_PROC_PRINT("IRQ breadcrumb:      %d\n",
+                              dev_priv->sarea_priv->last_dispatch);
+       } else {
+               DRM_PROC_PRINT("IRQ breadcrumb:      sarea uninitialized\n");
+       }
+
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
+static int i915_gem_fb_read(char *buf, char **start, off_t offset,
+                       int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       int len = 0;
+       int pipe;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       pipe = i915_debug_fb_pipe(dev);
+
+       *start = &buf[offset];
+       *eof = 0;
+       DRM_PROC_PRINT("Frame buffer pipe:   %d\n", pipe);
        if (len > request + offset)
                return request;
        *eof = 1;
        return len - offset;
 }
 
+#define LINE_SIZE      80
+
+static int i915_gem_fb_write(struct file *file, const char __user *buffer,
+                        unsigned long count, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       char line[LINE_SIZE];
+       char *end;
+       int pipe;
+       int ret;
+
+       if (!count)
+               return -EINVAL;
+       memset(line, 0, LINE_SIZE);
+       if (count > LINE_SIZE)
+               count = LINE_SIZE;
+       if (copy_from_user(line, buffer, count - 1))
+               return -EFAULT;
+       pipe = simple_strtol(line, &end, 10);
+       if (end == line)
+               return -EINVAL;
+       DRM_ERROR("line %s pipe %d\n", line, pipe);
+       switch (pipe) {
+       case 0:
+       case 1:
+               i915_debug_fb_destroy(dev);
+               ret = i915_debug_fb_create(dev, pipe);
+               break;
+       case -1:
+               ret = i915_debug_fb_destroy(dev);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       if (ret == 0)
+               ret = count;
+       return ret;
+}
+
 static struct drm_proc_list {
        /** file name */
        const char *name;
@@ -267,6 +344,19 @@ static struct drm_proc_list {
 
 #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
 
+static struct drm_rw_proc_list {
+       /** file name */
+       const char *name;
+       /** proc callback*/
+       int (*read) (char *, char **, off_t, int, int *, void *);
+       int (*write) (struct file *file, const char __user *buffer,
+                     unsigned long len, void *data);
+} i915_gem_proc_rw_list[] = {
+       {"i915_gem_fb", i915_gem_fb_read, i915_gem_fb_write},
+};
+
+#define I915_GEM_PROC_RW_ENTRIES ARRAY_SIZE(i915_gem_proc_rw_list)
+
 int i915_gem_proc_init(struct drm_minor *minor)
 {
        struct proc_dir_entry *ent;
@@ -286,6 +376,20 @@ int i915_gem_proc_init(struct drm_minor *minor)
                ent->read_proc = i915_gem_proc_list[i].f;
                ent->data = minor;
        }
+
+       for (i = 0; i < I915_GEM_PROC_RW_ENTRIES; i++) {
+               ent = create_proc_entry(i915_gem_proc_rw_list[i].name,
+                                       S_IFREG | S_IRUGO | S_IWUSR,
+                                       minor->dev_root);
+               if (!ent) {
+                       DRM_ERROR("Cannot create /proc/dri/.../%s\n",
+                                 i915_gem_proc_rw_list[i].name);
+                       return -1;
+               }
+               ent->read_proc = i915_gem_proc_rw_list[i].read;
+               ent->write_proc = i915_gem_proc_rw_list[i].write;
+               ent->data = minor;
+       }
        return 0;
 }
 
@@ -298,4 +402,6 @@ void i915_gem_proc_cleanup(struct drm_minor *minor)
 
        for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
                remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
+       for (i = 0; i < I915_GEM_PROC_RW_ENTRIES; i++)
+               remove_proc_entry(i915_gem_proc_rw_list[i].name, 
minor->dev_root);
 }
-- 
1.5.6.5


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to