[PATCH 1/4] DRM: in-kernel cursor update on the top of mode setting.

Tiago Vignatti vignatti at c3sl.ufpr.br
Mon Jan 5 12:58:13 PST 2009


This commit adds support for the DRM in-kernel cursor mode setting APIs.
When drm_mode_setcrtc is called we also initialize the cursor routines.
Through drmCursorSetDev, the userspace app (e.g. Xorg, wayland) tells which
devices are responsible for cursors' updates and the kernel input layer
will spit the events to DRM (drm_collect_input_event). DRM will take
care about the event informations and also screen limits, and then will
draw the cursor on screen.

Signed-off-by: Tiago Vignatti <vignatti at c3sl.ufpr.br>
---
 libdrm/xf86drm.c           |   20 ++++
 libdrm/xf86drm.h           |    4 +
 libdrm/xf86drmMode.c       |    4 +-
 linux-core/Makefile.kernel |    4 +-
 linux-core/drm_crtc.c      |    3 +
 linux-core/drm_crtc.h      |    4 +
 linux-core/drm_cursor.c    |  214 ++++++++++++++++++++++++++++++++++++++++++++
 linux-core/drm_cursorP.h   |    1 +
 linux-core/drm_drv.c       |    2 +
 shared-core/drm.h          |   11 +++
 10 files changed, 264 insertions(+), 3 deletions(-)
 create mode 100644 linux-core/drm_cursor.c
 create mode 100644 linux-core/drm_cursorP.h

diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c
index 7b67813..b8f12b6 100644
--- a/libdrm/xf86drm.c
+++ b/libdrm/xf86drm.c
@@ -2994,3 +2994,23 @@ int drmDropMaster(int fd)
 	ret = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0);
 	return ret;
 }
+
+int drmCursorSetDev(int fd, char *name)
+{
+    struct drm_mode_cursor_setdev arg;
+
+    strncpy(arg.name, name, strlen(name));
+    arg.name[strlen(name)] = '\0';
+
+    return ioctl(fd, DRM_IOCTL_MODE_CURSORSETDEV, &arg);
+}
+
+int drmCursorHotspot(int fd, int hotx, int hoty)
+{
+    struct drm_mode_cursor_hotspot arg;
+
+    arg.hotx = hotx;
+    arg.hoty = hoty;
+
+    return ioctl(fd, DRM_IOCTL_MODE_CURSORHOTSPOT, &arg);
+}
diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h
index 35780ac..04b7faa 100644
--- a/libdrm/xf86drm.h
+++ b/libdrm/xf86drm.h
@@ -663,6 +663,10 @@ extern void drmCloseOnce(int fd);
 extern int drmSetMaster(int fd);
 extern int drmDropMaster(int fd);
 
+/* In-kernel cursor update routines */
+extern int drmCursorSetDev(int fd, char *name);
+extern int drmCursorHotspot(int fd, int hotx, int hoty);
+
 #include "xf86mm.h"
 
 #endif
diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c
index c3921ee..e3a1c76 100644
--- a/libdrm/xf86drmMode.c
+++ b/libdrm/xf86drmMode.c
@@ -325,7 +325,9 @@ int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
 	arg.x = x;
 	arg.y = y;
 
-	return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
+/*	Just to see that we're doing the things correctly :)
+ *	return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); */
+    return 1;
 }
 
 /*
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index 246c0b3..53f5795 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -7,8 +7,8 @@
 # $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel,v 1.18 2003/08/16 17:59:17 dawes Exp $
 #
 
-drm-objs    := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
-		drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
+drm-objs    := drm_auth.o drm_bufs.o drm_context.o drm_cursor.o drm_dma.o \
+		drm_drawable.o drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
 		drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
 		drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \
 		drm_memory_debug.o ati_pcigart.o drm_sman.o \
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index 7ee3321..e015342 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -33,6 +33,7 @@
 #include "drm.h"
 #include "drmP.h"
 #include "drm_crtc.h"
+#include "drm_cursorP.h"
 
 struct drm_prop_enum_list {
 	int type;
@@ -1412,6 +1413,8 @@ int drm_mode_setcrtc(struct drm_device *dev,
 	set.fb =fb;
 	ret = crtc->funcs->set_config(&set);
 
+    drm_cursor_init(crtc);
+
 out:
 	kfree(connector_set);
 	mutex_unlock(&dev->mode_config.mutex);
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
index bfccdeb..15e9aca 100644
--- a/linux-core/drm_crtc.h
+++ b/linux-core/drm_crtc.h
@@ -676,6 +676,10 @@ 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_cursor_setdev_ioctl(struct drm_device *dev,
+                void *data, struct drm_file *file_priv);
+extern int drm_mode_cursor_hotspot_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_cursor.c b/linux-core/drm_cursor.c
new file mode 100644
index 0000000..832e3b1
--- /dev/null
+++ b/linux-core/drm_cursor.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2008 Tiago Vignatti <vignatti at c3sl.ufpr.br>
+ *
+ * DRM cursor and related functions
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Authors:
+ *      Tiago Vignatti <vignatti at c3sl.ufpr.br>
+ */
+
+#include <linux/drm_cursor.h>
+#include "drmP.h"
+#include "drm_cursorP.h"
+
+
+#define DEBUG_CURSOR 1
+
+/* XXX: define a sane max */
+#define MAX_INPUT_DEVICES 32
+
+char *cursor_devices[MAX_INPUT_DEVICES];
+int cursorReady = 0;
+
+struct drm_cursor {
+    struct drm_crtc *crtc;
+    int dx, dy;
+    int hotx, hoty;
+};
+struct drm_cursor *cursor = NULL;
+
+
+int drm_cursor_init(struct drm_crtc *crtc)
+{
+    int i, ret = 0;
+
+    DRM_DEBUG("\n");
+
+    cursor = kzalloc(sizeof(struct drm_cursor), GFP_KERNEL);
+    if (!cursor)
+        return -ENOMEM;
+
+    for (i = 0; i < MAX_INPUT_DEVICES; i++)
+        cursor_devices[i] = NULL;
+
+    cursor->crtc = crtc;
+    cursor->dx = crtc->fb->width / 2;
+    cursor->dy = crtc->fb->height / 2;
+    cursor->hotx = 0;
+    cursor->hoty = 0;
+
+    cursorReady = 1;
+
+    return ret;
+}
+
+int drm_mode_cursor_setdev_ioctl(struct drm_device *dev,
+            void *data, struct drm_file *file_priv)
+{
+    struct drm_mode_cursor_setdev *arg = data;
+    int ret = 0;
+    int i;
+
+    mutex_lock(&dev->mode_config.mutex);
+#ifdef DEBUG_CURSOR
+    printk("%s: %s\n", arg->name, __FUNCTION__);
+#endif
+    if (!arg->name) {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+        if (!cursor_devices[i]) {
+            cursor_devices[i] = kzalloc(sizeof(char) * strlen(arg->name), GFP_KERNEL);
+            if (!cursor_devices[i]) {
+                ret = -EINVAL;
+                goto out;
+            }
+
+            strncpy(cursor_devices[i], arg->name, strlen(arg->name));
+            cursor_devices[i][strlen(arg->name)] = '\0';
+            goto out;
+        }
+    }
+out:
+    mutex_unlock(&dev->mode_config.mutex);
+    return ret;
+}
+
+int drm_mode_cursor_hotspot_ioctl(struct drm_device *dev,
+            void *data, struct drm_file *file_priv)
+{
+    struct drm_mode_cursor_hotspot *arg = data;
+    struct drm_crtc *crtc;
+    int ret = 0;
+
+
+    mutex_lock(&dev->mode_config.mutex);
+    crtc = cursor->crtc;
+#ifdef DEBUG_CURSOR
+    printk("%s: %d %d\n", __FUNCTION__, arg->hotx, arg->hoty);
+#endif
+
+    cursor->hotx = arg->hotx;
+    cursor->hoty = arg->hoty;
+
+    /* Fake a movement to update the cursor's position */
+    if (crtc->funcs->cursor_move) {
+        ret = crtc->funcs->cursor_move(crtc, cursor->dx - cursor->hotx,
+                                       cursor->dy - cursor->hoty);
+    } else {
+        DRM_ERROR("crtc does not support cursor shorcut\n");
+        ret = -EFAULT;
+        goto out;
+    }
+
+out:
+    mutex_unlock(&dev->mode_config.mutex);
+    return ret;
+}
+
+static void clip_axis(int *val, int max_value)
+{
+    if (*val < 0)
+        *val = 0;
+    if (*val >= max_value)
+        *val = max_value - 1;
+}
+
+static int drm_is_cursor_dev(const char *name)
+{
+    int i;
+
+    for (i = 0; i < MAX_INPUT_DEVICES && cursor_devices[i]; i++) {
+        if (!strcmp(name, cursor_devices[i]))
+            return 1;
+    }
+    return 0;
+}
+
+void drm_collect_input_event(const char *name, struct input_event *ev)
+{
+    struct drm_crtc *crtc;
+    char evname[27];
+
+
+    crtc = cursor->crtc;
+    snprintf(evname, sizeof(evname), "/dev/input/%s", name);
+
+    if (!cursorReady)
+        return;
+    if (!drm_is_cursor_dev(evname))
+        return;
+
+    switch (ev->type) {
+    case EV_REL:
+        switch (ev->code) {
+        case REL_X:
+            cursor->dx += ev->value;
+            break;
+
+        case REL_Y:
+            cursor->dy += ev->value;
+            break;
+        }
+/* TODO: convert abs to rel motion */
+#if 0
+    case EV_ABS:
+        switch (ev->code) {
+        case ABS_X:
+            cursor->dx = ev->value;
+            break;
+        case ABS_Y:
+            cursor->dy = ev->value;
+            break;
+        }
+#endif
+    break;
+    }
+
+    clip_axis(&cursor->dx, crtc->fb->width);
+    clip_axis(&cursor->dy, crtc->fb->height);
+
+#ifdef DEBUG_CURSOR
+    printk("drm: dx:%d (%d), dy:%d (%d)\n", cursor->dx,
+                                            cursor->hotx,
+                                            cursor->dy,
+                                            cursor->hoty);
+#endif
+    if (crtc->funcs->cursor_move) {
+        crtc->funcs->cursor_move(crtc, cursor->dx - cursor->hotx,
+                                       cursor->dy - cursor->hoty);
+    } else {
+        DRM_ERROR("crtc does not support cursor shorcut\n");
+    }
+}
+EXPORT_SYMBOL(drm_collect_input_event);
diff --git a/linux-core/drm_cursorP.h b/linux-core/drm_cursorP.h
new file mode 100644
index 0000000..3cdc73e
--- /dev/null
+++ b/linux-core/drm_cursorP.h
@@ -0,0 +1 @@
+int drm_cursor_init(struct drm_crtc *crtc);
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index 4e7c531..55891ee 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -128,6 +128,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSORSETDEV, drm_mode_cursor_setdev_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSORHOTSPOT, drm_mode_cursor_hotspot_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW),
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 4119064..d6290d1 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -1238,6 +1238,15 @@ struct drm_mode_crtc_lut {
 	uint64_t blue;
 };
 
+struct drm_mode_cursor_setdev {
+    char name[32];
+};
+
+struct drm_mode_cursor_hotspot {
+    int hotx;
+    int hoty;
+};
+
 /**
  * \name Ioctls Definitions
  */
@@ -1356,6 +1365,8 @@ struct drm_mode_crtc_lut {
 #define DRM_IOCTL_MODE_GETENCODER      DRM_IOWR(0xB0, struct drm_mode_get_encoder)
 #define DRM_IOCTL_MODE_GETGAMMA        DRM_IOWR(0xB1, struct drm_mode_crtc_lut)
 #define DRM_IOCTL_MODE_SETGAMMA        DRM_IOWR(0xB2, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_CURSORSETDEV    DRM_IOWR(0xB3, struct drm_mode_cursor_setdev)
+#define DRM_IOCTL_MODE_CURSORHOTSPOT   DRM_IOWR(0xB4, struct drm_mode_cursor_hotspot)
 
 /*@}*/
 
-- 
1.5.6.3


-- 
Tiago Vignatti
C3SL - Centro de Computação Científica e Software Livre
www.c3sl.ufpr.br



More information about the xorg mailing list