Added cursor support
authorJakob Bornecrantz <jakob@tungstengraphics.com>
Mon, 28 Jan 2008 02:12:29 +0000 (03:12 +0100)
committerJakob Bornecrantz <jakob@tungstengraphics.com>
Mon, 28 Jan 2008 02:14:56 +0000 (03:14 +0100)
15 files changed:
libdrm/xf86drmMode.c
libdrm/xf86drmMode.h
linux-core/drm_crtc.c
linux-core/drm_crtc.h
linux-core/drm_drv.c
linux-core/intel_display.c
linux-core/intel_drv.h
linux-core/intel_fb.c
shared-core/drm.h
shared-core/i915_drv.h
shared-core/i915_init.c
tests/modedemo/demo.c
tests/modefb/Makefile [new file with mode: 0644]
tests/modefb/demo.c [new file with mode: 0644]
tests/modefb/test [new file with mode: 0755]

index 0edb1d7..8657287 100644 (file)
@@ -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
index e2dda8a..f5b3337 100644 (file)
@@ -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
index 1e69eca..18fa02c 100644 (file)
@@ -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
index 65c3704..8f6a893 100644 (file)
@@ -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,
index ab047ca..b0b44c9 100644 (file)
@@ -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),
index 1498a51..88cf653 100644 (file)
@@ -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;
 }
 
index 06335b1..25c3a97 100644 (file)
@@ -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];
 };
 
index b67c0fc..bb42bc6 100644 (file)
@@ -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;
 }
index 7aea303..209a8db 100644 (file)
@@ -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)
 
 /*@}*/
 
index 49e23ac..ea89bc4 100644 (file)
@@ -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;
index 3b271b1..792c40b 100644 (file)
@@ -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 =
index 594d60d..1efeb27 100644 (file)
@@ -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 (file)
index 0000000..84c6c86
--- /dev/null
@@ -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 (file)
index 0000000..0dbf01c
--- /dev/null
@@ -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 (executable)
index 0000000..f98e370
--- /dev/null
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app