aboutsummaryrefslogtreecommitdiffstats
path: root/drmtools.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2016-03-24 10:45:44 +0100
committerGerd Hoffmann <kraxel@redhat.com>2016-03-24 10:45:44 +0100
commit5e68ede72c48aeae3412e31e5633c03d48048deb (patch)
tree56025bf89ecf90085e09b40d3bfd2c65d0c9500d /drmtools.c
parent19c335cd7f53d759ec04e96e0d96ed7258f4521c (diff)
downloadfbida-5e68ede72c48aeae3412e31e5633c03d48048deb.tar.gz
drm code
Diffstat (limited to 'drmtools.c')
-rw-r--r--drmtools.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/drmtools.c b/drmtools.c
new file mode 100644
index 0000000..563aa3b
--- /dev/null
+++ b/drmtools.c
@@ -0,0 +1,188 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getopt.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "gfx.h"
+#include "drmtools.h"
+
+/* ------------------------------------------------------------------ */
+
+/* device */
+static int fd;
+static drmModeConnector *conn = NULL;
+static drmModeEncoder *enc = NULL;
+static drmModeModeInfo *mode = NULL;
+static drmModeCrtc *scrtc = NULL;
+static uint32_t fb_id;
+
+/* dumb fb */
+static struct drm_mode_create_dumb creq;
+static uint8_t *fbmem;
+
+/* ------------------------------------------------------------------ */
+
+static void drm_cleanup_display(void)
+{
+ /* restore crtc */
+ if (scrtc) {
+ drmModeSetCrtc(fd, scrtc->crtc_id, scrtc->buffer_id, scrtc->x, scrtc->y,
+ &conn->connector_id, 1, &scrtc->mode);
+ }
+}
+
+static int drm_init_dev(const char *dev)
+{
+ drmModeRes *res;
+ int i, rc;
+ uint64_t has_dumb;
+
+ /* open device */
+ fd = open(dev, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "drm: open %s: %s\n", dev, strerror(errno));
+ return -1;
+ }
+
+ rc = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
+ if (rc < 0 || !has_dumb) {
+ fprintf(stderr, "drm: no dumb buffer support\n");
+ return -1;
+ }
+
+ /* find connector (using first for now) */
+ res = drmModeGetResources(fd);
+ if (res == NULL) {
+ fprintf(stderr, "drm: drmModeGetResources() failed\n");
+ return -1;
+ }
+ for (i = 0; i < res->count_connectors; i++) {
+ conn = drmModeGetConnector(fd, res->connectors[i]);
+ if (conn &&
+ (conn->connection == DRM_MODE_CONNECTED) &&
+ conn->count_modes)
+ break;
+ drmModeFreeConnector(conn);
+ conn = NULL;
+ }
+ if (!conn) {
+ fprintf(stderr, "drm: no usable connector found\n");
+ return -1;
+ }
+ mode = &conn->modes[0];
+ enc = drmModeGetEncoder(fd, conn->encoder_id);
+ if (enc == NULL) {
+ fprintf(stderr, "drm: drmModeGetEncoder() failed\n");
+ return -1;
+ }
+
+ /* save crtc */
+ scrtc = drmModeGetCrtc(fd, enc->crtc_id);
+ return 0;
+}
+
+static int drm_init_fb(void)
+{
+ struct drm_mode_map_dumb mreq;
+ int rc;
+
+ /* create framebuffer */
+ memset(&creq, 0, sizeof(creq));
+ creq.width = mode->hdisplay;
+ creq.height = mode->vdisplay;
+ creq.bpp = 32;
+ rc = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
+ if (rc < 0) {
+ fprintf(stderr, "drm: DRM_IOCTL_MODE_CREATE_DUMB: %s\n", strerror(errno));
+ return -1;
+ }
+ rc = drmModeAddFB(fd, creq.width, creq.height, 24, 32, creq.pitch,
+ creq.handle, &fb_id);
+ if (rc < 0) {
+ fprintf(stderr, "drm: drmModeAddFB() failed\n");
+ return -1;
+ }
+
+ /* map framebuffer */
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.handle = creq.handle;
+ rc = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
+ if (rc < 0) {
+ fprintf(stderr, "drm: DRM_IOCTL_MODE_MAP_DUMB: %s\n", strerror(errno));
+ return -1;
+ }
+ fbmem = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
+ if (fbmem == MAP_FAILED) {
+ fprintf(stderr, "drm: framebuffer mmap: %s\n", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int drm_show_fb(void)
+{
+ int rc;
+
+ rc = drmModeSetCrtc(fd, enc->crtc_id, fb_id, 0, 0,
+ &conn->connector_id, 1,
+ &conn->modes[0]);
+ if (rc < 0) {
+ fprintf(stderr, "drm: drmModeSetCrtc() failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void drm_restore_display(void)
+{
+ drm_show_fb();
+}
+
+gfxstate *drm_init(const char *dev)
+{
+ gfxstate *gfx;
+
+ if (drm_init_dev(dev) < 0)
+ return NULL;
+ if (drm_init_fb() < 0)
+ return NULL;
+ if (drm_show_fb() < 0)
+ return NULL;
+
+ /* prepare gfx */
+ gfx = malloc(sizeof(*gfx));
+ memset(gfx, 0, sizeof(*gfx));
+
+ gfx->hdisplay = mode->hdisplay;
+ gfx->vdisplay = mode->vdisplay;
+ gfx->stride = creq.pitch;
+ gfx->mem = fbmem;
+
+ gfx->rlen = 8;
+ gfx->glen = 8;
+ gfx->blen = 8;
+ gfx->tlen = 8;
+ gfx->roff = 16;
+ gfx->goff = 8;
+ gfx->boff = 0;
+ gfx->toff = 24;
+ gfx->bits_per_pixel = 32;
+
+ gfx->restore_display = drm_restore_display;
+ gfx->cleanup_display = drm_cleanup_display;
+
+ return gfx;
+}