[Intel-gfx] [PATCH] [drm/i915] Add support for creating an fb device using one pipe

Keith Packard keithp at keithp.com
Mon Nov 3 08:39:03 CET 2008


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 <keithp at keithp.com>
---
 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 <keithp at keithp.com>
+ *
+ * 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




More information about the Intel-gfx mailing list