summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/dristat.c2
-rw-r--r--tests/mode/Makefile14
-rw-r--r--tests/mode/modetest.c380
-rwxr-xr-xtests/mode/test1
-rw-r--r--tests/modedemo/Makefile14
-rw-r--r--tests/modedemo/demo.c634
-rwxr-xr-xtests/modedemo/test1
-rw-r--r--tests/modefb/Makefile14
-rw-r--r--tests/modefb/demo.c231
-rwxr-xr-xtests/modefb/test1
-rw-r--r--tests/modehotplug/Makefile14
-rw-r--r--tests/modehotplug/demo.c157
-rwxr-xr-xtests/modehotplug/test1
13 files changed, 1463 insertions, 1 deletions
diff --git a/tests/dristat.c b/tests/dristat.c
index 89853164..48c3b51b 100644
--- a/tests/dristat.c
+++ b/tests/dristat.c
@@ -263,7 +263,7 @@ int main(int argc, char **argv)
for (i = 0; i < 16; i++) if (!minor || i == minor) {
sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, i);
- fd = drmOpenMinor(i, 1);
+ fd = drmOpenMinor(i, 1, DRM_NODE_RENDER);
if (fd >= 0) {
printf("%s\n", buf);
if (mask & DRM_BUSID) getbusid(fd);
diff --git a/tests/mode/Makefile b/tests/mode/Makefile
new file mode 100644
index 00000000..7a9c3c24
--- /dev/null
+++ b/tests/mode/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: modetest.c
+ @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c
+
+clean:
+ @rm -f app
+
+run: app
+ @sudo ./test
diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c
new file mode 100644
index 00000000..a50b0cc5
--- /dev/null
+++ b/tests/mode/modetest.c
@@ -0,0 +1,380 @@
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+int dpms_prop_id = 0;
+const char* getConnectionText(drmModeConnection conn)
+{
+ switch (conn) {
+ case DRM_MODE_CONNECTED:
+ return "connected";
+ case DRM_MODE_DISCONNECTED:
+ return "disconnected";
+ default:
+ return "unknown";
+ }
+
+}
+
+int printMode(struct drm_mode_modeinfo *mode)
+{
+#if 1
+ printf("Mode: %s\n", mode->name);
+ printf("\tclock : %i\n", mode->clock);
+ printf("\thdisplay : %i\n", mode->hdisplay);
+ printf("\thsync_start : %i\n", mode->hsync_start);
+ printf("\thsync_end : %i\n", mode->hsync_end);
+ printf("\thtotal : %i\n", mode->htotal);
+ printf("\thskew : %i\n", mode->hskew);
+ printf("\tvdisplay : %i\n", mode->vdisplay);
+ printf("\tvsync_start : %i\n", mode->vsync_start);
+ printf("\tvsync_end : %i\n", mode->vsync_end);
+ printf("\tvtotal : %i\n", mode->vtotal);
+ printf("\tvscan : %i\n", mode->vscan);
+ printf("\tvrefresh : %i\n", mode->vrefresh);
+ printf("\tflags : %i\n", mode->flags);
+#else
+ printf("Mode: \"%s\" %ix%i %.0f\n", mode->name,
+ mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0);
+#endif
+ return 0;
+}
+
+int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id)
+{
+ int i = 0, j;
+ struct drm_mode_modeinfo *mode = NULL;
+ drmModePropertyPtr props;
+ unsigned char *name = NULL;
+
+ printf("Output: %d-%d\n", output->output_type, output->output_type_id);
+ printf("\tid : %i\n", id);
+ printf("\tcrtc id : %i\n", output->crtc);
+ printf("\tconn : %s\n", getConnectionText(output->connection));
+ printf("\tsize : %ix%i (mm)\n", output->mmWidth, output->mmHeight);
+ printf("\tcount_crtcs : %i\n", output->count_crtcs);
+ printf("\tcrtcs : %i\n", output->crtcs);
+ printf("\tcount_clones : %i\n", output->count_clones);
+ printf("\tclones : %i\n", output->clones);
+ printf("\tcount_modes : %i\n", output->count_modes);
+ printf("\tcount_props : %i\n", output->count_props);
+
+ for (i = 0; i < output->count_props; i++) {
+ props = drmModeGetProperty(fd, output->props[i]);
+ name = NULL;
+ if (props) {
+ printf("Property: %s\n", props->name);
+ printf("\tid: %i\n", props->prop_id);
+ printf("\tflags: %i\n", props->flags);
+ printf("\tvalues %d: ", props->count_values);
+ for (j = 0; j < props->count_values; j++)
+ printf("%lld ", props->values[j]);
+
+ printf("\n\tenums %d: \n", props->count_enums);
+
+ if (props->flags & DRM_MODE_PROP_BLOB) {
+ drmModePropertyBlobPtr blob;
+
+ blob = drmModeGetPropertyBlob(fd, output->prop_values[i]);
+ if (blob) {
+ printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data);
+ drmModeFreePropertyBlob(blob);
+ }
+
+ } else {
+ if (!strncmp(props->name, "DPMS", 4))
+ dpms_prop_id = props->prop_id;
+
+ for (j = 0; j < props->count_enums; j++) {
+ printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name);
+ if (output->prop_values[i] == props->enums[j].value)
+ name = props->enums[j].name;
+
+ }
+
+ if (props->count_enums && name) {
+ printf("\toutput property name %s %s\n", props->name, name);
+ } else {
+ printf("\toutput property id %s %lli\n", props->name, output->prop_values[i]);
+ }
+ }
+
+ drmModeFreeProperty(props);
+ }
+ }
+
+ for (i = 0; i < output->count_modes; i++) {
+ mode = &output->modes[i];
+ if (mode)
+ printMode(mode);
+ else
+ printf("\t\tmode: Invalid mode %p\n", &output->modes[i]);
+ }
+
+ return 0;
+}
+
+int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id)
+{
+ printf("Crtc\n");
+ printf("\tid : %i\n", id);
+ printf("\tx : %i\n", crtc->x);
+ printf("\ty : %i\n", crtc->y);
+ printf("\twidth : %i\n", crtc->width);
+ printf("\theight : %i\n", crtc->height);
+ printf("\tmode : %p\n", &crtc->mode);
+ printf("\tnum outputs : %i\n", crtc->count_outputs);
+ printf("\toutputs : %i\n", crtc->outputs);
+ printf("\tnum possible : %i\n", crtc->count_possibles);
+ printf("\tpossibles : %i\n", crtc->possibles);
+
+ return 0;
+}
+
+int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb)
+{
+ printf("Framebuffer\n");
+ printf("\thandle : %i\n", fb->handle);
+ printf("\twidth : %i\n", fb->width);
+ printf("\theight : %i\n", fb->height);
+ printf("\tpitch : %i\n", fb->pitch);;
+ printf("\tbpp : %i\n", fb->bpp);
+ printf("\tdepth : %i\n", fb->depth);
+ printf("\tbuffer_id : %i\n", fb->buffer_id);
+
+ return 0;
+}
+
+int printRes(int fd, drmModeResPtr res)
+{
+ int i;
+ drmModeOutputPtr output;
+ drmModeCrtcPtr crtc;
+ drmModeFBPtr fb;
+
+ for (i = 0; i < res->count_outputs; i++) {
+ output = drmModeGetOutput(fd, res->outputs[i]);
+
+ if (!output)
+ printf("Could not get output %i\n", i);
+ else {
+ printOutput(fd, res, output, res->outputs[i]);
+ drmModeFreeOutput(output);
+ }
+ }
+
+ for (i = 0; i < res->count_crtcs; i++) {
+ crtc = drmModeGetCrtc(fd, res->crtcs[i]);
+
+ if (!crtc)
+ printf("Could not get crtc %i\n", i);
+ else {
+ printCrtc(fd, res, crtc, res->crtcs[i]);
+ drmModeFreeCrtc(crtc);
+ }
+ }
+
+ for (i = 0; i < res->count_fbs; i++) {
+ fb = drmModeGetFB(fd, res->fbs[i]);
+
+ if (!fb)
+ printf("Could not get fb %i\n", res->fbs[i]);
+ else {
+ printFrameBuffer(fd, res, fb);
+ drmModeFreeFB(fb);
+ }
+ }
+
+ return 0;
+}
+
+static struct drm_mode_modeinfo mode = {
+ .name = "Test 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,
+};
+
+int testMode(int fd, drmModeResPtr res)
+{
+ uint32_t output = res->outputs[0];
+ uint32_t newMode = 0;
+ int ret = 0;
+ int error = 0;
+
+ printf("Test: adding mode to output %i\n", output);
+
+ /* printMode(&mode); */
+
+ printf("\tAttaching mode %i to output %i\n", newMode, output);
+
+ ret = drmModeAttachMode(fd, output, &mode);
+
+ if (ret)
+ goto err_mode;
+
+ printf("\tDetaching mode %i from output %i\n", newMode, output);
+ ret = drmModeDetachMode(fd, output, &mode);
+
+ if (ret)
+ goto err_mode;
+ return 0;
+
+err_mode:
+
+ printf("\tFailed\n");
+
+ if (error)
+ printf("\tFailed to delete mode %i\n", newMode);
+ return 1;
+}
+
+/*
+int testFrameBufferGet(int fd, uint32_t fb)
+{
+ drmModeFBPtr frame;
+
+ printf("Test: get framebuffer %i\n", fb);
+
+ frame = drmModeGetFB(fd, fb);
+
+ if (!frame) {
+ printf("\tFailed\n");
+ } else {
+ printFrameBuffer(fd, frame);
+ drmModeFreeFB(frame);
+ }
+
+ return 0;
+}
+*/
+
+int testFrameBufferAdd(int fd, drmModeResPtr res)
+{
+ uint32_t fb = 0;
+ int ret = 0;
+ drmModeFBPtr frame = 0;
+ drmBO bo;
+
+ printf("Test: adding framebuffer\n");
+
+ printf("\tCreating BO\n");
+
+ /* TODO */
+ ret = drmBOCreate(fd, 800 * 600 * 4, 0, 0,
+ DRM_BO_FLAG_READ |
+ DRM_BO_FLAG_WRITE |
+ DRM_BO_FLAG_MEM_TT |
+ DRM_BO_FLAG_MEM_VRAM |
+ DRM_BO_FLAG_NO_EVICT,
+ DRM_BO_HINT_DONT_FENCE, &bo);
+
+ printf("\tgot %i\n", ret);
+ if (ret)
+ goto err;
+
+ printf("\tAdding FB\n");
+ ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, bo->handle, &fb);
+ if (ret)
+ goto err_bo;
+
+ frame = drmModeGetFB(fd, fb);
+
+ if (!frame) {
+ printf("Couldn't retrive created framebuffer\n");
+ } else {
+ printFrameBuffer(fd, res, frame);
+ drmModeFreeFB(frame);
+ }
+
+ printf("\tRemoveing FB\n");
+
+ ret = drmModeRmFB(fd, fb);
+
+ if (ret) {
+ printf("\tFailed this shouldn't happen!\n");
+ goto err_bo;
+ }
+
+ printf("\tRemoveing BO\n");
+
+ ret = drmBOUnreference(fb, &bo);
+
+ return 0;
+
+err_bo:
+ drmBOUnreference(fd, &bo);
+
+err:
+ printf("\tFailed\n");
+
+ return 1;
+}
+
+int testDPMS(int fd, drmModeResPtr res)
+{
+ int output_id;
+ int i;
+
+ for (i = 0; i < res->count_outputs; i++) {
+ output_id = res->outputs[i];
+ /* turn output off */
+ drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 3);
+ sleep(2);
+ drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 0);
+ }
+ return 1;
+
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ drmModeResPtr res;
+
+ printf("Starting test\n");
+
+ fd = drmOpenControl(0);
+
+ if (fd < 0) {
+ printf("Failed to open the card fb (%d)\n",fd);
+ return 1;
+ }
+
+ res = drmModeGetResources(fd);
+ if (res == 0) {
+ printf("Failed to get resources from card\n");
+ drmClose(fd);
+ return 1;
+ }
+
+ printRes(fd, res);
+
+ testMode(fd, res);
+
+ testFrameBufferAdd(fd, res);
+
+ /* try dpms test */
+ testDPMS(fd, res);
+ drmModeFreeResources(res);
+ printf("Ok\n");
+
+ return 0;
+}
diff --git a/tests/mode/test b/tests/mode/test
new file mode 100755
index 00000000..f98e3708
--- /dev/null
+++ b/tests/mode/test
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app
diff --git a/tests/modedemo/Makefile b/tests/modedemo/Makefile
new file mode 100644
index 00000000..467fb11a
--- /dev/null
+++ b/tests/modedemo/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 -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c
+
+clean:
+ @rm -f app
+
+run: app
+ sudo ./test
diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c
new file mode 100644
index 00000000..3fad984d
--- /dev/null
+++ b/tests/modedemo/demo.c
@@ -0,0 +1,634 @@
+/*
+ * Some defines to define the behavior of the program
+ */
+
+#define CLEAN_FBDEV
+#undef DEMO_CLONE
+
+#define SIZE_X 2048
+#define SIZE_Y 2048
+/* Pitch needs to be power of two */
+#define PITCH 2048
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef CLEAN_FBDEV
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#endif
+#include <signal.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+/* old functions to be replaced */
+drmModeFBPtr createFB(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, unsigned int color);
+
+#ifdef CLEAN_FBDEV
+struct fb_var_screeninfo var;
+struct fb_fix_screeninfo fix;
+#endif
+
+/* structs for the demo_driver */
+
+struct demo_driver;
+
+struct demo_screen
+{
+ /* drm stuff */
+ drmBO buffer;
+ drmModeFBPtr fb;
+ drmModeCrtcPtr crtc;
+
+ size_t num_outputs;
+ uint32_t outputs_id[8];
+ drmModeOutputPtr outputs[8];
+
+ struct drm_mode_modeinfo *mode;
+
+ /* virtual buffer */
+ uint32_t virt_x;
+ uint32_t virt_y;
+ uint32_t pitch;
+
+ /* parent */
+ struct demo_driver *driver;
+};
+
+#define DEMO_MAX_SCREENS 4
+#define MAX_FIND_OUTPUTS 8
+
+struct demo_driver
+{
+ /* drm stuff */
+ int fd;
+ drmModeResPtr res;
+
+ /* screens */
+ size_t numScreens;
+ struct demo_screen screens[DEMO_MAX_SCREENS];
+};
+
+struct demo_driver* demoCreateDriver(void);
+void demoUpdateRes(struct demo_driver *driver);
+int demoCreateScreens(struct demo_driver *driver);
+int demoCreateScreenCloned(struct demo_driver *driver);
+void demoTakeDownScreen(struct demo_screen *screen);
+int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out);
+drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output);
+void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y);
+/* yet to be implemented */
+void demoMouseActivate(struct demo_screen *screen);
+void demoMouseMove(struct demo_screen *screen, uint16_t x, uint16_t y);
+
+static struct drm_mode_modeinfo mode = {
+ .name = "Test 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,
+};
+
+int main(int argc, char **argv)
+{
+ struct demo_driver *driver;
+ int num;
+ int i;
+
+#ifdef CLEAN_FBDEV
+ int fbdev_fd;
+
+ fbdev_fd = open("/dev/fb0", O_RDWR);
+
+ memset(&var, 0, sizeof(struct fb_var_screeninfo));
+ memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &var))
+ printf("var %s\n", strerror(errno));
+ if (ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fix))
+ printf("fix %s\n", strerror(errno));
+#endif
+
+ printf("starting demo\n");
+
+ driver = demoCreateDriver();
+
+ if (!driver) {
+ printf("failed to create driver\n");
+ return 1;
+ }
+
+#ifndef DEMO_CLONE
+ num = demoCreateScreens(driver);
+#else
+ num = demoCreateScreenCloned(driver);
+#endif
+
+ if (num < 1) {
+ printf("no screens attached or an error occured\n");
+ return 1;
+ }
+ printf("created %i screens\n", num);
+
+ for (i = 0; i < num; i++) {
+ prettyColors(driver->fd, driver->screens[i].fb->handle);
+ }
+ sleep(1);
+
+ for (i = 0; i < num; i++) {
+ printf("%i: 100 0\n", i);
+ demoPanScreen(&driver->screens[i], 100, 0);
+ sleep(1);
+
+ printf("%i: 0 100\n", i);
+ demoPanScreen(&driver->screens[i], 0, 100);
+ sleep(1);
+
+ printf("%i: 100 100\n", i);
+ demoPanScreen(&driver->screens[i], 100, 100);
+ sleep(1);
+
+ printf("%i: 0 0\n", i);
+ demoPanScreen(&driver->screens[i], 0, 1);
+ sleep(1);
+ testCursor(driver->fd, driver->screens[i].crtc->crtc_id);
+ }
+
+ sleep(2);
+ printf("taking down screens\n");
+ for (i = 0; i < num; i++) {
+ demoTakeDownScreen(&driver->screens[i]);
+ }
+
+#ifdef CLEAN_FBDEV
+ if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &var))
+ printf("var %s\n", strerror(errno));
+
+ close(fbdev_fd);
+#endif
+
+ printf("ok\n");
+ return 0;
+}
+
+int demoCreateScreens(struct demo_driver *driver)
+{
+ drmModeOutputPtr out[MAX_FIND_OUTPUTS];
+ int num;
+ int num_screens = 0;
+ struct demo_screen *screen;
+ int ret = 0;
+ int i;
+
+ num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS);
+ if (num < 0)
+ return 0;
+
+ printf("found %i connected outputs\n", num);
+
+ for (i = 0; i < num; i++) {
+ screen = &driver->screens[i];
+
+ screen->crtc = demoFindFreeCrtc(driver, out[i]);
+ if (!screen->crtc) {
+ printf("found no free crtc for output\n");
+ drmModeFreeOutput(out[i]);
+ continue;
+ }
+
+ screen->fb = createFB(driver->fd, driver->res);
+ if (!screen->fb) {
+ drmModeFreeOutput(out[i]);
+ drmModeFreeCrtc(screen->crtc);
+ screen->crtc = 0;
+ printf("could not create framebuffer\n");
+ continue;
+ }
+
+ screen->virt_x = SIZE_X;
+ screen->virt_y = SIZE_Y;
+ screen->pitch = PITCH;
+
+ screen->outputs[0] = out[i];
+ screen->outputs_id[0] = out[i]->output_id;
+ screen->num_outputs = 1;
+
+ screen->mode = &mode;
+ screen->driver = driver;
+
+ ret = drmModeSetCrtc(
+ driver->fd,
+ screen->crtc->crtc_id,
+ screen->fb->buffer_id,
+ 0, 0,
+ screen->outputs_id, screen->num_outputs,
+ screen->mode);
+
+ if (ret) {
+ printf("failed to set mode\n");
+ demoTakeDownScreen(screen);
+ } else {
+ num_screens++;
+ }
+
+ demoUpdateRes(driver);
+ }
+
+ return num_screens;
+}
+
+int demoCreateScreenCloned(struct demo_driver *driver)
+{
+ drmModeOutputPtr out[MAX_FIND_OUTPUTS];
+ int num;
+ struct demo_screen *screen;
+ int ret = 0;
+ int i;
+
+ num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS);
+ if (num < 0)
+ return 0;
+
+ printf("found %i connected outputs\n", num);
+
+ screen = &driver->screens[0];
+
+ screen->fb = createFB(driver->fd, driver->res);
+ if (!screen->fb) {
+ printf("could not create framebuffer\n");
+ return 0;
+ }
+
+ screen->mode = &mode;
+ screen->driver = driver;
+
+ screen->virt_x = SIZE_X;
+ screen->virt_y = SIZE_Y;
+ screen->pitch = PITCH;
+
+ screen->num_outputs = 0;
+ for (i = 0; i < num; i++) {
+ screen->crtc = demoFindFreeCrtc(driver, out[i]);
+ if (!screen->crtc) {
+ printf("found no free crtc for output\n");
+ drmModeFreeOutput(out[i]);
+ continue;
+ }
+
+ screen->outputs[screen->num_outputs] = out[i];
+ screen->outputs_id[screen->num_outputs] = out[i]->output_id;
+ screen->num_outputs++;
+ printf("%u, %u\n", out[i]->output_id, screen->num_outputs);
+ }
+
+ ret = drmModeSetCrtc(
+ driver->fd,
+ screen->crtc->crtc_id,
+ screen->fb->buffer_id,
+ 0, 0,
+ screen->outputs_id, screen->num_outputs,
+ screen->mode);
+
+ if (ret) {
+ printf("failed to set mode\n");
+ demoTakeDownScreen(screen);
+ return 0;
+ }
+
+ demoUpdateRes(driver);
+
+ return 1;
+}
+
+void demoTakeDownScreen(struct demo_screen *screen)
+{
+ int fd = screen->driver->fd;
+ int i;
+ drmBO bo;
+
+#if 0
+ /* This can bust the fbdev arrangement as it basically unhooks
+ * the outputs and the fbdev backend doesn't know how to put things
+ * back on track. Realistically, it's up to the crtc owner to restore
+ * things.....
+ *
+ * So if you are mixing API's make sure the modesetting owner puts
+ * back the original CRTC arrangement so fbdev can continue...
+ *
+ * Ho-hum..
+ */
+ if (screen->crtc)
+ drmModeSetCrtc(fd, screen->crtc->crtc_id, 0, 0, 0, 0, 0, 0);
+#endif
+
+ if (screen->fb)
+ drmModeRmFB(fd, screen->fb->buffer_id);
+
+ /* maybe we should keep a pointer to the bo on the screen */
+ if (screen->fb && !drmBOReference(fd, screen->fb->handle, &bo)) {
+ drmBOUnreference(fd, &bo);
+ drmBOUnreference(fd, &bo);
+ } else {
+ printf("bo error\n");
+ }
+
+ for (i = 0; i < screen->num_outputs; i++) {
+ drmModeFreeOutput(screen->outputs[i]);
+ screen->outputs[i] = NULL;
+ }
+
+ drmModeFreeCrtc(screen->crtc);
+ drmModeFreeFB(screen->fb);
+
+ screen->crtc = NULL;
+ screen->fb = NULL;
+}
+
+drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output)
+{
+ drmModeCrtcPtr crtc;
+ int i, j, used = 0;
+ drmModeResPtr res = driver->res;
+
+ for (i = 0; i < res->count_crtcs; i++) {
+ used = 0;
+ for (j = 0; j < DEMO_MAX_SCREENS; j++) {
+ crtc = driver->screens[j].crtc;
+
+ if (crtc && crtc->crtc_id == res->crtcs[i])
+ used = 1;
+ }
+
+ if (!used) {
+ crtc = drmModeGetCrtc(driver->fd, res->crtcs[i]);
+ break;
+ } else {
+ crtc = 0;
+ }
+ }
+
+ return crtc;
+}
+
+static int driverfd;
+
+static void
+hotplugSIGNAL(int sig, siginfo_t *si, void *d)
+{
+ union drm_wait_hotplug hw;
+ int ret;
+
+ printf("GOT HOTPLUG EVENT!\n");
+
+ /* ask for another hotplug event ! */
+ memset(&hw, 0, sizeof(hw));
+ hw.request.type = _DRM_HOTPLUG_SIGNAL;
+ hw.request.signal = SIGUSR1;
+ ret = ioctl(driverfd, DRM_IOCTL_WAIT_HOTPLUG, &hw);
+}
+
+struct demo_driver* demoCreateDriver(void)
+{
+ struct demo_driver* driver = malloc(sizeof(struct demo_driver));
+ union drm_wait_hotplug hw;
+ int ret = 0;
+
+ memset(driver, 0, sizeof(struct demo_driver));
+
+ driver->fd = drmOpen("i915",NULL);
+
+ if (driver->fd < 0) {
+ printf("Failed to open the card fb\n");
+ goto err_driver;
+ }
+
+#if 0
+ /* ioctl wait for hotplug */
+ do {
+ memset(&hw, 0, sizeof(hw));
+ ret = ioctl(driver->fd, DRM_IOCTL_WAIT_HOTPLUG, &hw);
+ printf("HOTPLUG %d %d %d\n",ret,errno,hw.reply.counter);
+ } while (ret && errno == EBUSY);
+#else
+ /* signal for hotplug */
+ {
+ struct sigaction sa;
+ struct sigaction osa;
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = hotplugSIGNAL;
+ sigaction(SIGUSR1, &sa, &osa);
+
+ driverfd = driver->fd;
+
+ memset(&hw, 0, sizeof(hw));
+ hw.request.type = _DRM_HOTPLUG_SIGNAL;
+ hw.request.signal = SIGUSR1;
+ ret = ioctl(driver->fd, DRM_IOCTL_WAIT_HOTPLUG, &hw);
+ }
+#endif
+
+ demoUpdateRes(driver);
+ if (!driver->res) {
+ printf("could not retrive resources\n");
+ goto err_res;
+ }
+
+ return driver;
+
+err_res:
+ drmClose(driver->fd);
+err_driver:
+ free(driver);
+ return NULL;
+}
+
+void demoUpdateRes(struct demo_driver *driver)
+{
+ if (driver->res)
+ drmModeFreeResources(driver->res);
+
+ driver->res = drmModeGetResources(driver->fd);
+
+ if (!driver->res)
+ printf("failed to get resources from kernel\n");
+}
+
+int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out)
+{
+ int count = 0;
+ int i,j;
+ int fd = driver->fd;
+ drmModeResPtr res = driver->res;
+
+ drmModeOutputPtr output;
+
+ for (i = 0; i < res->count_outputs && count < max_out; i++) {
+ output = drmModeGetOutput(fd, res->outputs[i]);
+
+ if (!output)
+ continue;
+
+ if (output->connection == DRM_MODE_DISCONNECTED) {
+ drmModeFreeOutput(output);
+ continue;
+ }
+
+ for (j = 0; j < output->count_props; j++) {
+ drmModePropertyPtr prop;
+
+ prop = drmModeGetProperty(fd, output->props[j]);
+
+ printf("Property: %s\n",prop->name);
+ if (prop->count_enums)
+ printf("%s\n",prop->enums[output->prop_values[j]].name);
+ }
+
+ out[count++] = output;
+ }
+
+ return count;
+}
+
+void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y)
+{
+ drmModeSetCrtc(
+ screen->driver->fd,
+ screen->crtc->crtc_id,
+ screen->fb->buffer_id,
+ x, y,
+ screen->outputs_id, screen->num_outputs,
+ screen->mode);
+}
+
+drmModeFBPtr createFB(int fd, drmModeResPtr res)
+{
+ drmModeFBPtr frame;
+ unsigned int fb = 0;
+ int ret = 0;
+ drmBO bo;
+
+ ret = drmBOCreate(fd, SIZE_X * SIZE_Y * 4, 0, 0,
+ DRM_BO_FLAG_READ |
+ DRM_BO_FLAG_WRITE |
+ DRM_BO_FLAG_MEM_TT |
+ DRM_BO_FLAG_MEM_VRAM |
+ DRM_BO_FLAG_NO_EVICT,
+ DRM_BO_HINT_DONT_FENCE, &bo);
+
+ if (ret) {
+ printf("failed to create framebuffer (ret %d)\n",ret);
+ goto err;
+ }
+
+ ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, bo.handle, &fb);
+
+ if (ret)
+ goto err_bo;
+
+ frame = drmModeGetFB(fd, fb);
+
+ if (!frame)
+ goto err_bo;
+
+ return frame;
+
+err_bo:
+ drmBOUnreference(fd, &bo);
+err:
+ return 0;
+}
+
+void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr)
+{
+ int i, j;
+
+ for (i = x; i < x + w; i++)
+ for(j = y; j < y + h; j++)
+ ptr[(i * PITCH) + j] = v;
+
+}
+
+void prettyColors(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 < (SIZE_X*SIZE_Y); i++)
+ ptr[i] = 0xFFFFFFFF;
+
+ for (i = 0; i < 8; i++)
+ draw(i * 40, i * 40, 40, 40, 0, ptr);
+
+
+ draw(200, 100, 40, 40, 0xff00ff, ptr);
+ draw(100, 200, 40, 40, 0xff00ff, ptr);
+
+ 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, 0xFFFF00FF);
+ printf("set cursor\n");
+ drmModeSetCursor(fd, crtc, &bo, 64, 64);
+ printf("move cursor 0, 0\n");
+ drmModeMoveCursor(fd, crtc, 0, 0);
+ sleep(1);
+ prettyCursor(fd, bo.handle, 0xFFFF0000);
+ printf("move cursor 40, 40\n");
+ drmModeMoveCursor(fd, crtc, 40, 40);
+ sleep(1);
+ printf("move cursor 100, 100\n");
+ drmModeMoveCursor(fd, crtc, 100, 100);
+ sleep(1);
+ drmModeSetCursor(fd, crtc, NULL, 0, 0);
+}
+
+void prettyCursor(int fd, unsigned int handle, unsigned int color)
+{
+ 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] = color;
+
+ drmBOUnmap(fd, &bo);
+ drmBOUnreference(fd, &bo);
+}
diff --git a/tests/modedemo/test b/tests/modedemo/test
new file mode 100755
index 00000000..f98e3708
--- /dev/null
+++ b/tests/modedemo/test
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app
diff --git a/tests/modefb/Makefile b/tests/modefb/Makefile
new file mode 100644
index 00000000..467fb11a
--- /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 -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm 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..b6d1f65b
--- /dev/null
+++ b/tests/modefb/demo.c
@@ -0,0 +1,231 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include "linux/fb.h"
+#include <sys/mman.h>
+#include "sys/ioctl.h"
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+void pretty(int fd);
+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 drmfd);
+void prettyColors(int fd);
+void prettyCursor(int fd, unsigned int handle, unsigned int color);
+
+extern void sleep(int);
+
+struct fb_var_screeninfo var;
+struct fb_fix_screeninfo fix;
+
+int main(int argc, char **argv)
+{
+ char name[100];
+ int i,d;
+ int fd;
+ int drmfd = drmOpen("i915", NULL);
+
+ if (drmfd < 0) {
+ printf("drmOpenControl failed\n");
+ return 1;
+ }
+
+ /* try four devices */
+ for (d = 0; d < 4; d++) {
+ snprintf(name, 100, "/dev/fb%d", d);
+ fd = open(name, O_RDWR);
+
+ 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);
+
+ if (ioctl(fd, FBIOPUT_VSCREENINFO, &var))
+ printf("var %s\n", strerror(errno));
+
+ for (i = 0; i < 1; i++) {
+ prettyColors(fd);
+ }
+ sleep(1);
+
+ 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 (may show up on wrong CRTC - fixme)\n");
+ cursor(fd, drmfd);
+
+ close(fd);
+ }
+ return 0;
+}
+
+void pan(int fd, struct fb_var_screeninfo *var, int x, int y)
+{
+ var->xoffset = x;
+ var->yoffset = y;
+
+ if (ioctl(fd, FBIOPAN_DISPLAY, var))
+ printf("pan error: %s\n", strerror(errno));
+}
+
+void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr)
+{
+ int i, j;
+
+ for (i = x; i < x + w; i++)
+ for(j = y; j < y + h; j++)
+ ptr[(i * var.xres_virtual) + j] = v;
+}
+
+void prettyColors(int fd)
+{
+ unsigned int *ptr;
+ int i;
+ int size = var.xres * var.yres * var.bits_per_pixel;
+
+ ptr = (unsigned int *)mmap(NULL, size,
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd,
+ 0);
+ if (ptr < 0) {
+ printf("FAILED MMAP %d\n",errno);
+ exit(1);
+ }
+
+ memset(ptr, 0xFF, size);
+
+ for (i = 0; i < 8; i++)
+ draw(i * 40, i * 40, 40, 40, 0, ptr);
+
+
+ draw(200, 100, 40, 40, 0xff00ff, ptr);
+ draw(100, 200, 40, 40, 0xff00ff, ptr);
+
+ munmap(ptr, size);
+}
+
+/*
+ * Cursor support removed from the fb kernel interface
+ * using drm instead.
+ */
+void cursor(int fd, int drmfd)
+{
+ drmModeResPtr res = drmModeGetResources(drmfd);
+ uint32_t crtc = res->crtcs[1]; /* select crtc here */
+ drmBO bo;
+ int ret;
+ ret = drmBOCreate(drmfd, 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);
+
+ if (ret) {
+ printf("failed to create buffer: %s\n", strerror(ret));
+ return;
+ }
+
+ prettyCursor(drmfd, bo.handle, 0xFFFF00FF);
+ drmModeSetCursor(drmfd, crtc, &bo, 64, 64);
+ drmModeMoveCursor(drmfd, crtc, 0, 0);
+ sleep(1);
+ prettyCursor(drmfd, bo.handle, 0xFFFF0000);
+ drmModeMoveCursor(drmfd, crtc, 40, 40);
+ sleep(1);
+ drmModeMoveCursor(drmfd, crtc, 100, 100);
+ sleep(1);
+ drmModeSetCursor(drmfd, crtc, NULL, 0, 0);
+ drmBOUnreference(drmfd, &bo);
+}
+
+void prettyCursor(int drmfd, unsigned int handle, unsigned int color)
+{
+ drmBO bo;
+ unsigned int *ptr;
+ int i;
+
+ drmBOReference(drmfd, handle, &bo);
+ drmBOMap(drmfd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr);
+
+ for (i = 0; i < (64 * 64); i++)
+ ptr[i] = color;
+
+ drmBOUnmap(drmfd, &bo);
+ drmBOUnreference(drmfd, &bo);
+}
+
+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;
+ var->bits_per_pixel = 32;
+}
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
diff --git a/tests/modehotplug/Makefile b/tests/modehotplug/Makefile
new file mode 100644
index 00000000..467fb11a
--- /dev/null
+++ b/tests/modehotplug/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 -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c
+
+clean:
+ @rm -f app
+
+run: app
+ sudo ./test
diff --git a/tests/modehotplug/demo.c b/tests/modehotplug/demo.c
new file mode 100644
index 00000000..4ef2e386
--- /dev/null
+++ b/tests/modehotplug/demo.c
@@ -0,0 +1,157 @@
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+/* structs for the demo_driver */
+
+#define DEMO_MAX_OUTPUTS 8
+
+struct demo_driver
+{
+ /* drm stuff */
+ int fd;
+ drmModeResPtr res;
+ uint32_t counter;
+
+ drmModeOutputPtr outputs[DEMO_MAX_OUTPUTS];
+};
+
+struct demo_driver* demoCreateDriver(void);
+void demoUpdateRes(struct demo_driver *driver);
+
+void demoPopulateOutputs(struct demo_driver *driver);
+void demoHotplug(struct demo_driver *driver);
+
+const char* demoGetStatus(drmModeOutputPtr out);
+
+int main(int argc, char **argv)
+{
+ struct demo_driver *driver;
+ uint32_t temp;
+ int i;
+
+ printf("starting demo\n");
+
+ driver = demoCreateDriver();
+
+ if (!driver) {
+ printf("failed to create driver\n");
+ return 1;
+ }
+
+ driver->counter = drmModeGetHotplug(driver->fd);
+ demoPopulateOutputs(driver);
+ while (driver->counter != (temp = drmModeGetHotplug(driver->fd))) {
+ demoPopulateOutputs(driver);
+ driver->counter = temp;
+ }
+
+ for (i = 0; i < driver->res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) {
+ printf("Output %u is %s\n",
+ driver->outputs[i]->output_id,
+ demoGetStatus(driver->outputs[i]));
+ }
+
+ while(1) {
+ usleep(100000);
+ temp = drmModeGetHotplug(driver->fd);
+ if (temp == driver->counter)
+ continue;
+
+ demoHotplug(driver);
+ driver->counter = temp;
+ }
+
+ return 0;
+}
+
+const char* demoGetStatus(drmModeOutputPtr output)
+{
+ switch (output->connection) {
+ case DRM_MODE_CONNECTED:
+ return "connected";
+ case DRM_MODE_DISCONNECTED:
+ return "disconnected";
+ default:
+ return "unknown";
+ }
+}
+
+void demoHotplug(struct demo_driver *driver)
+{
+ drmModeResPtr res = driver->res;
+ int i;
+ drmModeOutputPtr temp, current;
+
+ for (i = 0; i < res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) {
+ temp = drmModeGetOutput(driver->fd, res->outputs[i]);
+ current = driver->outputs[i];
+
+ if (temp->connection != current->connection) {
+ printf("Output %u became %s was %s\n",
+ temp->output_id,
+ demoGetStatus(temp),
+ demoGetStatus(current));
+ }
+
+ drmModeFreeOutput(current);
+ driver->outputs[i] = temp;
+ }
+}
+
+void demoPopulateOutputs(struct demo_driver *driver)
+{
+ drmModeResPtr res = driver->res;
+ int i;
+
+ for (i = 0; i < res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) {
+ drmModeFreeOutput(driver->outputs[i]);
+ driver->outputs[i] = drmModeGetOutput(driver->fd, res->outputs[i]);
+ }
+}
+
+struct demo_driver* demoCreateDriver(void)
+{
+ struct demo_driver* driver = malloc(sizeof(struct demo_driver));
+
+ memset(driver, 0, sizeof(struct demo_driver));
+
+ driver->fd = drmOpen("i915", NULL);
+
+ if (driver->fd < 0) {
+ printf("Failed to open the card fb\n");
+ goto err_driver;
+ }
+
+ demoUpdateRes(driver);
+ if (!driver->res) {
+ printf("could not retrive resources\n");
+ goto err_res;
+ }
+
+ return driver;
+
+err_res:
+ drmClose(driver->fd);
+err_driver:
+ free(driver);
+ return NULL;
+}
+
+void demoUpdateRes(struct demo_driver *driver)
+{
+ if (driver->res)
+ drmModeFreeResources(driver->res);
+
+ driver->res = drmModeGetResources(driver->fd);
+
+ if (!driver->res)
+ printf("failed to get resources from kernel\n");
+}
diff --git a/tests/modehotplug/test b/tests/modehotplug/test
new file mode 100755
index 00000000..f98e3708
--- /dev/null
+++ b/tests/modehotplug/test
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app