summaryrefslogtreecommitdiff
path: root/src/drm_fb.c
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2018-01-01 22:43:06 -0800
committerVito Caputo <vcaputo@pengaru.com>2018-01-01 22:43:06 -0800
commit9618a7cca221e8959a920ec13148a7e6bd2e9b7a (patch)
tree0bba74477176e9b66d7da1963792d0e4fb4a16e2 /src/drm_fb.c
parent9e5f4de8ecc1408fe8b65f5eee442a38322b8ac8 (diff)
drm_fb: implement drm fb backend
Largely mechanical copying of the drm code into the new fb_ops_t abstraction. Dormant for now.
Diffstat (limited to 'src/drm_fb.c')
-rw-r--r--src/drm_fb.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/drm_fb.c b/src/drm_fb.c
new file mode 100644
index 0000000..99169de
--- /dev/null
+++ b/src/drm_fb.c
@@ -0,0 +1,157 @@
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "fb.h"
+#include "util.h"
+
+
+/* drm fb backend, everything drm-specific in rototiller resides here. */
+
+typedef struct drm_fb_t {
+ int drm_fd;
+ uint32_t crtc_id;
+ uint32_t *connectors;
+ int n_connectors;
+ drmModeModeInfoPtr mode;
+} drm_fb_t;
+
+typedef struct drm_fb_page_t drm_fb_page_t;
+
+struct drm_fb_page_t {
+ uint32_t *mmap;
+ size_t mmap_size;
+ uint32_t drm_dumb_handle;
+ uint32_t drm_fb_id;
+};
+
+
+drm_fb_t * drm_fb_new(int drm_fd, uint32_t crtc_id, uint32_t *connectors, int n_connectors, drmModeModeInfoPtr mode)
+{
+ drm_fb_t *c;
+
+ c = calloc(1, sizeof(drm_fb_t));
+ if (!c)
+ return NULL;
+
+ c->drm_fd = drm_fd;
+ c->crtc_id = crtc_id;
+ c->connectors = connectors;
+ c->n_connectors = n_connectors;
+ c->mode = mode;
+
+ return c;
+}
+
+
+void drm_fb_free(drm_fb_t *context)
+{
+ free(context);
+}
+
+
+static int drm_fb_acquire(void *context, void *page)
+{
+ drm_fb_t *c = context;
+ drm_fb_page_t *p = page;
+
+ return drmModeSetCrtc(c->drm_fd, c->crtc_id, p->drm_fb_id, 0, 0, c->connectors, c->n_connectors, c->mode);
+}
+
+
+static void drm_fb_release(void *context)
+{
+ /* TODO restore the existing mode @ last acquire? */
+}
+
+
+static void * drm_fb_page_alloc(void *context, fb_page_t *res_page)
+{
+ struct drm_mode_create_dumb create_dumb = { .bpp = 32 };
+ struct drm_mode_map_dumb map_dumb = {};
+ uint32_t *map, fb_id;
+ drm_fb_t *c = context;
+ drm_fb_page_t *p;
+
+ p = calloc(1, sizeof(drm_fb_page_t));
+ if (!p)
+ return NULL;
+
+ create_dumb.width = c->mode->hdisplay;
+ create_dumb.height = c->mode->vdisplay;
+
+ pexit_if(ioctl(c->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) < 0,
+ "unable to create dumb buffer");
+
+ map_dumb.handle = create_dumb.handle;
+ pexit_if(ioctl(c->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb) < 0,
+ "unable to prepare dumb buffer for mmap");
+ pexit_if(!(map = mmap(NULL, create_dumb.size, PROT_READ|PROT_WRITE, MAP_SHARED, c->drm_fd, map_dumb.offset)),
+ "unable to mmap dumb buffer");
+ pexit_if(drmModeAddFB(c->drm_fd, c->mode->hdisplay, c->mode->vdisplay, 24, 32, create_dumb.pitch, create_dumb.handle, &fb_id) < 0,
+ "unable to add dumb buffer");
+
+ p->mmap = map;
+ p->mmap_size = create_dumb.size;
+ p->drm_dumb_handle = map_dumb.handle;
+ p->drm_fb_id = fb_id;
+
+ res_page->fragment.buf = map;
+ res_page->fragment.width = c->mode->hdisplay;
+ res_page->fragment.frame_width = c->mode->hdisplay;
+ res_page->fragment.height = c->mode->vdisplay;
+ res_page->fragment.frame_height = c->mode->vdisplay;
+ res_page->fragment.stride = create_dumb.pitch - (c->mode->hdisplay * 4);
+
+ return p;
+}
+
+
+static int drm_fb_page_free(void *context, void *page)
+{
+ struct drm_mode_destroy_dumb destroy_dumb = {};
+ drm_fb_t *c = context;
+ drm_fb_page_t *p = page;
+
+ drmModeRmFB(c->drm_fd, p->drm_fb_id);
+ munmap(p->mmap, p->mmap_size);
+
+ destroy_dumb.handle = p->drm_dumb_handle;
+ ioctl(c->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb); // XXX: errors?
+
+ free(p);
+
+ return 0;
+}
+
+
+static int drm_fb_page_flip(void *context, void *page)
+{
+ drmEventContext drm_ev_ctx = {
+ .version = DRM_EVENT_CONTEXT_VERSION,
+ .vblank_handler = NULL,
+ .page_flip_handler = NULL
+ };
+ drm_fb_t *c = context;
+ drm_fb_page_t *p = page;
+
+ if (drmModePageFlip(c->drm_fd, c->crtc_id, p->drm_fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL) < 0)
+ return -1;
+
+ return drmHandleEvent(c->drm_fd, &drm_ev_ctx);
+}
+
+
+fb_ops_t drm_fb_ops = {
+ .acquire = drm_fb_acquire,
+ .release = drm_fb_release,
+ .page_alloc = drm_fb_page_alloc,
+ .page_free = drm_fb_page_free,
+ .page_flip = drm_fb_page_flip
+};
© All Rights Reserved