summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@tungstengraphics.com>2008-01-28 03:12:29 +0100
committerJakob Bornecrantz <jakob@tungstengraphics.com>2008-01-28 03:14:56 +0100
commita2254c5a9670a3e865f0eb5acd46e905c9b146ce (patch)
tree080e144b12585dc3dd4c7e3cae63bb3dbe004486
parent98361cf28c62530e34758b27aa1eea805269e0e5 (diff)
Added cursor support
-rw-r--r--libdrm/xf86drmMode.c28
-rw-r--r--libdrm/xf86drmMode.h13
-rw-r--r--linux-core/drm_crtc.c57
-rw-r--r--linux-core/drm_crtc.h22
-rw-r--r--linux-core/drm_drv.c1
-rw-r--r--linux-core/intel_display.c108
-rw-r--r--linux-core/intel_drv.h1
-rw-r--r--linux-core/intel_fb.c26
-rw-r--r--shared-core/drm.h28
-rw-r--r--shared-core/i915_drv.h1
-rw-r--r--shared-core/i915_init.c5
-rw-r--r--tests/modedemo/demo.c47
-rw-r--r--tests/modefb/Makefile14
-rw-r--r--tests/modefb/demo.c150
-rwxr-xr-xtests/modefb/test1
15 files changed, 494 insertions, 8 deletions
diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c
index 0edb1d7d..86572872 100644
--- a/libdrm/xf86drmMode.c
+++ b/libdrm/xf86drmMode.c
@@ -317,6 +317,34 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
}
+/*
+ * Cursor manipulation
+ */
+
+int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height)
+{
+ struct drm_mode_cursor arg;
+
+ arg.flags = DRM_MODE_CURSOR_BO;
+ arg.crtc = crtcId;
+ arg.width = width;
+ arg.height = height;
+ arg.handle = bo->handle;
+
+ return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
+}
+
+int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
+{
+ struct drm_mode_cursor arg;
+
+ arg.flags = DRM_MODE_CURSOR_MOVE;
+ arg.crtc = crtcId;
+ arg.x = x;
+ arg.y = y;
+
+ return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
+}
/*
* Output manipulation
diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h
index e2dda8ac..f5b3337c 100644
--- a/libdrm/xf86drmMode.h
+++ b/libdrm/xf86drmMode.h
@@ -197,6 +197,19 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
uint32_t x, uint32_t y, uint32_t *outputs, int count,
struct drm_mode_modeinfo *mode);
+/*
+ * Cursor functions
+ */
+
+/**
+ * Set the cursor on crtc
+ */
+int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height);
+
+/**
+ * Move the cursor on crtc
+ */
+int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y);
/*
* Output manipulation
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index 1e69eca3..18fa02ce 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -1608,6 +1608,63 @@ out:
return ret;
}
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ struct drm_mode_cursor *req = data;
+ struct drm_crtc *crtc;
+ struct drm_buffer_object *bo = NULL; /* must be set */
+ int ret = 0;
+
+ DRM_DEBUG("\n");
+
+ if (!req->flags) {
+ DRM_ERROR("no operation set\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->mode_config.mutex);
+ crtc = idr_find(&dev->mode_config.crtc_idr, req->crtc);
+ if (!crtc || (crtc->id != req->crtc)) {
+ DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (req->flags & DRM_MODE_CURSOR_BO) {
+ /* Turn of the cursor if handle is 0 */
+ if (req->handle)
+ ret = drm_get_buffer_object(dev, &bo, req->handle);
+
+ if (ret) {
+ DRM_ERROR("invalid buffer id\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (crtc->funcs->cursor_set) {
+ ret = crtc->funcs->cursor_set(crtc, bo, req->width, req->height);
+ } else {
+ DRM_ERROR("crtc does not support cursor\n");
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ if (req->flags & DRM_MODE_CURSOR_MOVE) {
+ if (crtc->funcs->cursor_move) {
+ ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
+ } else {
+ DRM_ERROR("crtc does not support cursor\n");
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&dev->mode_config.mutex);
+ return ret;
+}
+
/**
* drm_mode_addfb - add an FB to the graphics configuration
* @inode: inode from the ioctl
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
index 65c3704a..8f6a8938 100644
--- a/linux-core/drm_crtc.h
+++ b/linux-core/drm_crtc.h
@@ -329,6 +329,11 @@ struct drm_crtc_funcs {
/* Move the crtc on the current fb to the given position *optional* */
void (*mode_set_base)(struct drm_crtc *crtc, int x, int y);
+ /* cursor controls */
+ int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo,
+ uint32_t width, uint32_t height);
+ int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
+
/* Set gamma on the CRTC */
void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
int regno);
@@ -483,6 +488,21 @@ struct drm_output {
};
/**
+ * struct drm_mode_set
+ *
+ * Represents a single crtc the outputs that it drives with what mode
+ * and from which framebuffer it scans out from.
+ */
+struct drm_mode_set
+{
+ struct drm_framebuffer *fb;
+ struct drm_crtc *crtc;
+
+ struct drm_output **outputs;
+ size_t num_outputs;
+};
+
+/**
* struct drm_mode_config_funcs - configure CRTCs for a given screen layout
* @resize: adjust CRTCs as necessary for the proposed layout
*
@@ -603,6 +623,8 @@ extern int drm_mode_getoutput(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_setcrtc(struct drm_device *dev,
void *data, struct drm_file *file_priv);
+extern int drm_mode_cursor_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
extern int drm_mode_addfb(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_rmfb(struct drm_device *dev,
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index ab047ca3..b0b44c90 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -125,6 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c
index 1498a51c..88cf653c 100644
--- a/linux-core/intel_display.c
+++ b/linux-core/intel_display.c
@@ -402,6 +402,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
}
}
+
+
/**
* Sets the power management mode of the pipe and plane.
*
@@ -956,6 +958,108 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
}
}
+#define CURSOR_A_CONTROL 0x70080
+#define CURSOR_A_BASE 0x70084
+#define CURSOR_A_POSITION 0x70088
+
+#define CURSOR_B_CONTROL 0x700C0
+#define CURSOR_B_BASE 0x700C4
+#define CURSOR_B_POSITION 0x700C8
+
+#define CURSOR_MODE_DISABLE 0x00
+#define CURSOR_MODE_64_32B_AX 0x07
+#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX)
+#define MCURSOR_GAMMA_ENABLE (1 << 26)
+
+#define CURSOR_POS_MASK 0x007FF
+#define CURSOR_POS_SIGN 0x8000
+#define CURSOR_X_SHIFT 0
+#define CURSOR_Y_SHIFT 16
+
+static int intel_crtc_cursor_set(struct drm_crtc *crtc,
+ struct drm_buffer_object *bo,
+ uint32_t width, uint32_t height)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = crtc->driver_private;
+ int pipe = intel_crtc->pipe;
+ uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL;
+ uint32_t temp;
+ size_t adder;
+
+ DRM_DEBUG("\n");
+
+ /* if we want to turn of the cursor ignore width and height */
+ if (!bo) {
+ DRM_DEBUG("cursor off\n");
+ /* turn of the cursor */
+ temp = 0;
+ temp |= CURSOR_MODE_DISABLE;
+
+ I915_WRITE(control, temp);
+ return 0;
+ }
+
+ /* Currently we only support 64x64 cursors */
+ if (width != 64 || height != 64) {
+ DRM_ERROR("we currently only support 64x64 cursors\n");
+ return -EINVAL;
+ }
+
+ if ((bo->mem.flags & DRM_BO_MASK_MEM) != DRM_BO_FLAG_MEM_VRAM) {
+ DRM_ERROR("buffer needs to be in VRAM\n");
+ return -ENOMEM;
+ }
+
+ if (bo->mem.size < width * height * 4) {
+ DRM_ERROR("buffer is to small\n");
+ return -ENOMEM;
+ }
+
+ adder = dev_priv->stolen_base + bo->offset;
+ intel_crtc->cursor_adder = adder;
+ temp = 0;
+ /* set the pipe for the cursor */
+ temp |= (pipe << 28);
+ temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+
+ DRM_DEBUG("cusror base %x\n", adder);
+
+ I915_WRITE((pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL, temp);
+ I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder);
+
+ return 0;
+}
+
+static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = crtc->driver_private;
+ int pipe = intel_crtc->pipe;
+ uint32_t temp = 0;
+ uint32_t adder;
+
+ if (x < 0) {
+ temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
+ x = -x;
+ }
+ if (y < 0) {
+ temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
+ y = -y;
+ }
+
+ temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
+ temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+
+ adder = intel_crtc->cursor_adder;
+ I915_WRITE((pipe == 0) ? CURSOR_A_POSITION : CURSOR_B_POSITION, temp);
+ I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder);
+
+ return 0;
+}
+
/** Sets the color ramps on behalf of RandR */
static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno)
@@ -1084,6 +1188,8 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.mode_fixup = intel_crtc_mode_fixup,
.mode_set = intel_crtc_mode_set,
.mode_set_base = intel_pipe_set_base,
+ .cursor_set = intel_crtc_cursor_set,
+ .cursor_move = intel_crtc_cursor_move,
.gamma_set = intel_crtc_gamma_set,
.prepare = intel_crtc_prepare,
.commit = intel_crtc_commit,
@@ -1113,6 +1219,8 @@ void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc->lut_b[i] = i;
}
+ intel_crtc->cursor_adder = 0;
+
crtc->driver_private = intel_crtc;
}
diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h
index 06335b18..25c3a978 100644
--- a/linux-core/intel_drv.h
+++ b/linux-core/intel_drv.h
@@ -55,6 +55,7 @@ struct intel_output {
struct intel_crtc {
int pipe;
+ uint32_t cursor_adder;
u8 lut_r[256], lut_g[256], lut_b[256];
};
diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c
index b67c0fcc..bb42bc69 100644
--- a/linux-core/intel_fb.c
+++ b/linux-core/intel_fb.c
@@ -49,7 +49,7 @@ struct intelfb_par {
struct drm_crtc *crtc;
struct drm_display_mode *fb_mode;
};
-
+/*
static int
var_to_refresh(const struct fb_var_screeninfo *var)
{
@@ -59,7 +59,7 @@ var_to_refresh(const struct fb_var_screeninfo *var)
var->vsync_len;
return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
-}
+}*/
static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
@@ -106,10 +106,10 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct intelfb_par *par = info->par;
- struct drm_device *dev = par->dev;
+ /*struct drm_device *dev = par->dev;*/
struct drm_framebuffer *fb = par->crtc->fb;
- struct drm_output *output;
- int depth, found = 0;
+ /*struct drm_output *output;*/
+ int depth/*, found = 0*/;
if (!var->pixclock)
return -EINVAL;
@@ -254,6 +254,8 @@ static int intelfb_set_par(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
int found = 0;
+ DRM_DEBUG("\n");
+
switch (var->bits_per_pixel) {
case 16:
fb->depth = (var->green.length == 6) ? 16 : 15;
@@ -321,9 +323,19 @@ static int intelfb_set_par(struct fb_info *info)
}
if (par->crtc->enabled) {
- if (!drm_mode_equal(&par->crtc->mode, drm_mode))
- if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
+ if (!drm_mode_equal(&par->crtc->mode, drm_mode)) {
+ if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset))
return -EINVAL;
+ } else if (par->crtc->x != var->xoffset || par->crtc->x != var->xoffset) {
+ if (!par->crtc->funcs->mode_set_base) {
+ if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset))
+ return -EINVAL;
+ } else {
+ par->crtc->funcs->mode_set_base(par->crtc, var->xoffset, var->yoffset);
+ par->crtc->x = var->xoffset;
+ par->crtc->y = var->yoffset;
+ }
+ }
}
return 0;
}
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 7aea3033..209a8db0 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -1084,6 +1084,33 @@ struct drm_mode_mode_cmd {
struct drm_mode_modeinfo mode;
};
+#define DRM_MODE_CURSOR_BO 0x01
+#define DRM_MODE_CURSOR_MOVE 0x02
+
+/*
+ * depending on the value in flags diffrent members are used.
+ *
+ * CURSOR_BO uses
+ * crtc
+ * width
+ * height
+ * handle - if 0 turns the cursor of
+ *
+ * CURSOR_MOVE uses
+ * crtc
+ * x
+ * y
+ */
+struct drm_mode_cursor {
+ unsigned int flags;
+ unsigned int crtc;
+ int x;
+ int y;
+ uint32_t width;
+ uint32_t height;
+ unsigned int handle;
+};
+
/**
* \name Ioctls Definitions
*/
@@ -1190,6 +1217,7 @@ struct drm_mode_mode_cmd {
#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd)
#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property)
+#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xAC, struct drm_mode_cursor)
/*@}*/
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 49e23ac3..ea89bc4c 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -147,6 +147,7 @@ struct drm_i915_private {
void *agp_iomap;
unsigned int max_validate_buffers;
struct mutex cmdbuf_mutex;
+ size_t stolen_base;
#endif
DRM_SPINTYPE swaps_lock;
diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c
index 3b271b17..792c40bb 100644
--- a/shared-core/i915_init.c
+++ b/shared-core/i915_init.c
@@ -132,6 +132,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev->types[9] = _DRM_STAT_DMA;
if (IS_I9XX(dev)) {
+ pci_read_config_dword(dev->pdev, 0x5C, &dev_priv->stolen_base);
+ DRM_DEBUG("stolen base %p\n", (void*)dev_priv->stolen_base);
+ }
+
+ if (IS_I9XX(dev)) {
dev_priv->mmiobase = drm_get_resource_start(dev, 0);
dev_priv->mmiolen = drm_get_resource_len(dev, 0);
dev->mode_config.fb_base =
diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c
index 594d60db..1efeb272 100644
--- a/tests/modedemo/demo.c
+++ b/tests/modedemo/demo.c
@@ -34,7 +34,9 @@ static struct drm_mode_modeinfo mode = {
drmModeFBPtr createFB(int fd, drmModeResPtr res);
int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out);
drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res);
+void testCursor(int fd, uint32_t crtc);
void prettyColors(int fd, unsigned int handle);
+void prettyCursor(int fd, unsigned int handle);
int main(int argc, char **argv)
{
@@ -98,6 +100,11 @@ int main(int argc, char **argv)
drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 100, &out[0]->output_id, 1, &mode);
sleep(2);
+ printf("0 0\n");
+ drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 1, 1, &out[0]->output_id, 1, &mode);
+
+ testCursor(fd, crtc->crtc_id);
+
/* turn the crtc off just in case */
drmModeSetCrtc(fd, crtc->crtc_id, 0, 0, 0, 0, 0, 0);
@@ -166,7 +173,7 @@ int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out)
drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res)
{
- return drmModeGetCrtc(fd, res->crtcs[0]);
+ return drmModeGetCrtc(fd, res->crtcs[1]);
}
void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr)
@@ -200,3 +207,41 @@ void prettyColors(int fd, unsigned int handle)
drmBOUnmap(fd, &bo);
}
+
+void testCursor(int fd, uint32_t crtc)
+{
+ drmBO bo;
+ int ret;
+ ret = drmBOCreate(fd, 64 * 64 * 4, 0, 0,
+ DRM_BO_FLAG_READ |
+ DRM_BO_FLAG_WRITE |
+ DRM_BO_FLAG_MEM_VRAM |
+ DRM_BO_FLAG_NO_EVICT,
+ DRM_BO_HINT_DONT_FENCE, &bo);
+
+ prettyCursor(fd, bo.handle);
+
+ printf("set cursor\n");
+ drmModeSetCursor(fd, crtc, &bo, 64, 64);
+ printf("move cursor 0, 0\n");
+ drmModeMoveCursor(fd, crtc, 0, 0);
+ sleep(2);
+ printf("move cursor 40, 40\n");
+ drmModeMoveCursor(fd, crtc, 40, 40);
+ sleep(2);
+}
+
+void prettyCursor(int fd, unsigned int handle)
+{
+ drmBO bo;
+ unsigned int *ptr;
+ int i;
+
+ drmBOReference(fd, handle, &bo);
+ drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr);
+
+ for (i = 0; i < (64 * 64); i++)
+ ptr[i] = 0xFFFF00FF;
+
+ drmBOUnmap(fd, &bo);
+}
diff --git a/tests/modefb/Makefile b/tests/modefb/Makefile
new file mode 100644
index 00000000..84c6c86a
--- /dev/null
+++ b/tests/modefb/Makefile
@@ -0,0 +1,14 @@
+
+all: app
+
+#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \
+# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \
+
+app: demo.c
+ @gcc $(CFLAGS) -o app -Wall demo.c
+
+clean:
+ @rm -f app
+
+run: app
+ sudo ./test
diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c
new file mode 100644
index 00000000..0dbf01c7
--- /dev/null
+++ b/tests/modefb/demo.c
@@ -0,0 +1,150 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include "linux/fb.h"
+#include "sys/ioctl.h"
+
+
+void setMode(struct fb_var_screeninfo *var);
+void pan(int fd, struct fb_var_screeninfo *var, int x, int y);
+void cursor(int fd);
+
+int main(int argc, char **argv)
+{
+ struct fb_var_screeninfo var;
+ struct fb_fix_screeninfo fix;
+ const char* name = "/dev/fb0";
+
+ int fd = open(name, O_RDONLY);
+
+ if (fd == -1) {
+ printf("open %s : %s\n", name, strerror(errno));
+ return 1;
+ }
+
+ memset(&var, 0, sizeof(struct fb_var_screeninfo));
+ memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &var))
+ printf("var %s\n", strerror(errno));
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &fix))
+ printf("fix %s\n", strerror(errno));
+
+ setMode(&var);
+ printf("pan: 0, 0\n");
+ pan(fd, &var, 0, 0);
+ sleep(2);
+ printf("pan: 100, 0\n");
+ pan(fd, &var, 100, 0);
+ sleep(2);
+ printf("pan: 0, 100\n");
+ pan(fd, &var, 0, 100);
+ sleep(2);
+ printf("pan: 100, 100\n");
+ pan(fd, &var, 100, 100);
+ sleep(2);
+ printf("pan: 0, 0\n");
+ pan(fd, &var, 0, 0);
+ sleep(2);
+
+ printf("cursor\n");
+ cursor(fd);
+ return 0;
+}
+
+void pan(int fd, struct fb_var_screeninfo *var, int x, int y)
+{
+ var->xoffset = x;
+ var->yoffset = y;
+
+ var->activate = FB_ACTIVATE_NOW;
+
+ if (ioctl(fd, FBIOPUT_VSCREENINFO, var))
+ printf("pan error: %s\n", strerror(errno));
+}
+
+/*
+ * Currently isn't supported in the driver
+ */
+void cursor(int fd)
+{
+ struct fb_cursor cur;
+ void *data = malloc(64 * 64 * 4);
+ memset(&cur, 0, sizeof(cur));
+
+ cur.set = FB_CUR_SETIMAGE | FB_CUR_SETPOS | FB_CUR_SETSIZE;
+ cur.enable = 1;
+ cur.image.dx = 1;
+ cur.image.dy = 1;
+ cur.image.width = 2;
+ cur.image.height = 2;
+ cur.image.depth = 32;
+ cur.image.data = data;
+
+ if (ioctl(fd, FBIO_CURSOR, &cur))
+ printf("cursor error: %s\n", strerror(errno));
+
+ sleep(2);
+
+ memset(&cur, 0, sizeof(cur));
+ cur.set = FB_CUR_SETPOS;
+ cur.enable = 0;
+ cur.image.dx = 100;
+ cur.image.dy = 100;
+
+ if (ioctl(fd, FBIO_CURSOR, &cur))
+ printf("cursor error: %s\n", strerror(errno));
+
+ free(data);
+}
+
+struct drm_mode
+{
+ int clock;
+ int hdisplay;
+ int hsync_start;
+ int hsync_end;
+ int htotal;
+ int hskew;
+ int vdisplay;
+ int vsync_start;
+ int vsync_end;
+ int vtotal;
+ int vscan;
+ int vrefresh;
+ int flags;
+};
+
+struct drm_mode mode =
+{
+ .clock = 25200,
+ .hdisplay = 640,
+ .hsync_start = 656,
+ .hsync_end = 752,
+ .htotal = 800,
+ .hskew = 0,
+ .vdisplay = 480,
+ .vsync_start = 490,
+ .vsync_end = 492,
+ .vtotal = 525,
+ .vscan = 0,
+ .vrefresh = 60000, /* vertical refresh * 1000 */
+ .flags = 10,
+};
+
+void setMode(struct fb_var_screeninfo *var) {
+ var->activate = FB_ACTIVATE_NOW;
+ var->xres = mode.hdisplay;
+ var->right_margin = mode.hsync_start - mode.hdisplay;
+ var->hsync_len = mode.hsync_end - mode.hsync_start;
+ var->left_margin = mode.htotal - mode.hsync_end;
+ var->yres = mode.vdisplay;
+ var->lower_margin = mode.vsync_start - mode.vdisplay;
+ var->vsync_len = mode.vsync_end - mode.vsync_start;
+ var->upper_margin = mode.vtotal - mode.vsync_end;
+ var->pixclock = 10000000 / mode.htotal * 1000 / mode.vtotal * 100;
+ /* avoid overflow */
+ var->pixclock = var->pixclock * 1000 / mode.vrefresh;
+}
diff --git a/tests/modefb/test b/tests/modefb/test
new file mode 100755
index 00000000..f98e3708
--- /dev/null
+++ b/tests/modefb/test
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app