uterm: video: use shl_dlist for linked lists
authorDavid Herrmann <dh.herrmann@googlemail.com>
Sat, 12 Jan 2013 12:31:17 +0000 (13:31 +0100)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Sat, 12 Jan 2013 12:31:17 +0000 (13:31 +0100)
uterm-video is actually older than shl_dlist and it used its own
single-linked lists until now. This had several drawbacks and produced
ugly code.

This commit converts all uterm-video elements to use shl_dlist and
introduces _bind and _unbind helpers.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/uterm_drm_shared.c
src/uterm_drm_shared_internal.h
src/uterm_fbdev_internal.h
src/uterm_fbdev_render.c
src/uterm_fbdev_video.c
src/uterm_video.c
src/uterm_video_drm.c
src/uterm_video_dumb.c
src/uterm_video_internal.h

index 3a55b05..90069de 100644 (file)
@@ -285,12 +285,8 @@ int uterm_drm_display_set_dpms(struct uterm_display *disp, int state)
 {
        int ret;
        struct uterm_drm_display *ddrm = disp->data;
-       struct uterm_drm_video *vdrm;
-
-       if (!display_is_conn(disp) || !video_is_awake(disp->video))
-               return -EINVAL;
+       struct uterm_drm_video *vdrm = disp->video->data;
 
-       vdrm = disp->video->data;
        log_info("setting DPMS of display %p to %s", disp,
                 uterm_dpms_to_name(state));
 
@@ -302,53 +298,6 @@ int uterm_drm_display_set_dpms(struct uterm_display *disp, int state)
        return 0;
 }
 
-int uterm_drm_display_bind(struct uterm_video *video,
-                          struct uterm_display *disp, drmModeRes *res,
-                          drmModeConnector *conn, int fd)
-{
-       struct uterm_mode *mode;
-       int ret, i;
-       struct uterm_drm_display *ddrm = disp->data;
-
-       for (i = 0; i < conn->count_modes; ++i) {
-               ret = mode_new(&mode, &uterm_drm_mode_ops);
-               if (ret)
-                       continue;
-               uterm_drm_mode_set(mode, &conn->modes[i]);
-               mode->next = disp->modes;
-               disp->modes = mode;
-
-               /* TODO: more sophisticated default-mode selection */
-               if (!disp->default_mode)
-                       disp->default_mode = mode;
-       }
-
-       if (!disp->modes) {
-               log_warn("no valid mode for display found");
-               return -EFAULT;
-       }
-
-       ddrm->conn_id = conn->connector_id;
-       disp->flags |= DISPLAY_AVAILABLE;
-       disp->next = video->displays;
-       video->displays = disp;
-       disp->dpms = uterm_drm_get_dpms(fd, conn);
-
-       log_info("display %p DPMS is %s", disp,
-                uterm_dpms_to_name(disp->dpms));
-
-       VIDEO_CB(video, disp, UTERM_NEW);
-       return 0;
-}
-
-void uterm_drm_display_unbind(struct uterm_display *disp)
-{
-       VIDEO_CB(disp->video, disp, UTERM_GONE);
-       uterm_display_deactivate(disp);
-       disp->video = NULL;
-       disp->flags &= ~DISPLAY_AVAILABLE;
-}
-
 static void event(struct ev_fd *fd, int mask, void *data)
 {
        struct uterm_video *video = data;
@@ -427,16 +376,20 @@ int uterm_drm_video_find_crtc(struct uterm_video *video, drmModeRes *res,
        int i, crtc;
        struct uterm_display *iter;
        struct uterm_drm_display *ddrm;
+       struct shl_dlist *it;
 
        for (i = 0; i < res->count_crtcs; ++i) {
                if (enc->possible_crtcs & (1 << i)) {
                        crtc = res->crtcs[i];
-                       for (iter = video->displays; iter; iter = iter->next) {
+                       shl_dlist_for_each(it, &video->displays) {
+                               iter = shl_dlist_entry(it,
+                                                      struct uterm_display,
+                                                      list);
                                ddrm = iter->data;
                                if (ddrm->crtc_id == crtc)
                                        break;
                        }
-                       if (!iter)
+                       if (it == &video->displays)
                                return crtc;
                }
        }
@@ -450,26 +403,58 @@ static void bind_display(struct uterm_video *video, drmModeRes *res,
 {
        struct uterm_drm_video *vdrm = video->data;
        struct uterm_display *disp;
-       int ret;
+       struct uterm_drm_display *ddrm;
+       struct uterm_mode *mode;
+       int ret, i;
 
-       ret = display_new(&disp, ops, video);
+       ret = display_new(&disp, ops);
        if (ret)
                return;
+       ddrm = disp->data;
 
-       ret = uterm_drm_display_bind(video, disp, res, conn, vdrm->fd);
-       if (ret) {
-               uterm_display_unref(disp);
-               return;
+       for (i = 0; i < conn->count_modes; ++i) {
+               ret = mode_new(&mode, &uterm_drm_mode_ops);
+               if (ret)
+                       continue;
+
+               uterm_drm_mode_set(mode, &conn->modes[i]);
+
+               ret = uterm_mode_bind(mode, disp);
+               if (ret) {
+                       uterm_mode_unref(mode);
+                       continue;
+               }
+
+               /* TODO: more sophisticated default-mode selection */
+               if (!disp->default_mode)
+                       disp->default_mode = mode;
+
+               uterm_mode_unref(mode);
        }
-}
 
-static void unbind_display(struct uterm_display *disp)
-{
-       if (!display_is_conn(disp))
-               return;
+       if (shl_dlist_empty(&disp->modes)) {
+               log_warn("no valid mode for display found");
+               ret = -EFAULT;
+               goto err_unref;
+       }
+
+       ddrm->conn_id = conn->connector_id;
+       disp->flags |= DISPLAY_AVAILABLE;
+       disp->dpms = uterm_drm_get_dpms(vdrm->fd, conn);
+
+       log_info("display %p DPMS is %s", disp,
+                uterm_dpms_to_name(disp->dpms));
+
+       ret = uterm_display_bind(disp, video);
+       if (ret)
+               goto err_unref;
 
-       uterm_drm_display_unbind(disp);
        uterm_display_unref(disp);
+       return;
+
+err_unref:
+       uterm_display_unref(disp);
+       return;
 }
 
 int uterm_drm_video_hotplug(struct uterm_video *video,
@@ -478,9 +463,10 @@ int uterm_drm_video_hotplug(struct uterm_video *video,
        struct uterm_drm_video *vdrm = video->data;
        drmModeRes *res;
        drmModeConnector *conn;
-       struct uterm_display *disp, *tmp;
+       struct uterm_display *disp;
        struct uterm_drm_display *ddrm;
        int i;
+       struct shl_dlist *iter, *tmp;
 
        if (!video_is_awake(video) || !video_need_hotplug(video))
                return 0;
@@ -491,22 +477,28 @@ int uterm_drm_video_hotplug(struct uterm_video *video,
                return -EACCES;
        }
 
-       for (disp = video->displays; disp; disp = disp->next)
+       shl_dlist_for_each(iter, &video->displays) {
+               disp = shl_dlist_entry(iter, struct uterm_display, list);
                disp->flags &= ~DISPLAY_AVAILABLE;
+       }
 
        for (i = 0; i < res->count_connectors; ++i) {
                conn = drmModeGetConnector(vdrm->fd, res->connectors[i]);
                if (!conn)
                        continue;
                if (conn->connection == DRM_MODE_CONNECTED) {
-                       for (disp = video->displays; disp; disp = disp->next) {
+                       shl_dlist_for_each(iter, &video->displays) {
+                               disp = shl_dlist_entry(iter,
+                                                      struct uterm_display,
+                                                      list);
                                ddrm = disp->data;
+
                                if (ddrm->conn_id == res->connectors[i]) {
                                        disp->flags |= DISPLAY_AVAILABLE;
                                        break;
                                }
                        }
-                       if (!disp)
+                       if (iter == &video->displays)
                                bind_display(video, res, conn, ops);
                }
                drmModeFreeConnector(conn);
@@ -514,24 +506,10 @@ int uterm_drm_video_hotplug(struct uterm_video *video,
 
        drmModeFreeResources(res);
 
-       while (video->displays) {
-               tmp = video->displays;
-               if (tmp->flags & DISPLAY_AVAILABLE)
-                       break;
-
-               video->displays = tmp->next;
-               tmp->next = NULL;
-               unbind_display(tmp);
-       }
-       for (disp = video->displays; disp && disp->next; ) {
-               tmp = disp->next;
-               if (tmp->flags & DISPLAY_AVAILABLE) {
-                       disp = tmp;
-               } else {
-                       disp->next = tmp->next;
-                       tmp->next = NULL;
-                       unbind_display(tmp);
-               }
+       shl_dlist_for_each_safe(iter, tmp, &video->displays) {
+               disp = shl_dlist_entry(iter, struct uterm_display, list);
+               if (!(disp->flags & DISPLAY_AVAILABLE))
+                       uterm_display_unbind(disp);
        }
 
        video->flags &= ~VIDEO_HOTPLUG;
@@ -553,7 +531,6 @@ int uterm_drm_video_wake_up(struct uterm_video *video,
        video->flags |= VIDEO_AWAKE;
        ret = uterm_drm_video_hotplug(video, ops);
        if (ret) {
-               video->flags &= ~VIDEO_AWAKE;
                drmDropMaster(vdrm->fd);
                return ret;
        }
@@ -566,7 +543,6 @@ void uterm_drm_video_sleep(struct uterm_video *video)
        struct uterm_drm_video *vdrm = video->data;
 
        drmDropMaster(vdrm->fd);
-       video->flags &= ~VIDEO_AWAKE;
 }
 
 int uterm_drm_video_poll(struct uterm_video *video,
index 6b857c2..199d5b3 100644 (file)
@@ -75,10 +75,6 @@ int uterm_drm_display_init(struct uterm_display *disp, void *data);
 void uterm_drm_display_destroy(struct uterm_display *disp);
 int uterm_drm_display_activate(struct uterm_display *disp, int fd);
 void uterm_drm_display_deactivate(struct uterm_display *disp, int fd);
-int uterm_drm_display_bind(struct uterm_video *video,
-                          struct uterm_display *disp, drmModeRes *res,
-                          drmModeConnector *conn, int fd);
-void uterm_drm_display_unbind(struct uterm_display *disp);
 int uterm_drm_display_set_dpms(struct uterm_display *disp, int state);
 
 static inline void *uterm_drm_display_get_data(struct uterm_display *disp)
index c4257c7..b0ac72e 100644 (file)
@@ -41,13 +41,11 @@ struct fbdev_mode {
 };
 
 struct fbdev_display {
-       char *node;
        int fd;
-       bool pending_intro;
-
        struct fb_fix_screeninfo finfo;
        struct fb_var_screeninfo vinfo;
        unsigned int rate;
+       const char *node;
 
        unsigned int bufid;
        size_t xres;
@@ -69,6 +67,12 @@ struct fbdev_display {
        int_fast32_t dither_b;
 };
 
+struct fbdev_video {
+       char *node;
+       bool pending_intro;
+       struct uterm_display *disp;
+};
+
 int uterm_fbdev_display_blit(struct uterm_display *disp,
                             const struct uterm_video_buffer *buf,
                             unsigned int x, unsigned int y);
index f441153..ad96ad3 100644 (file)
@@ -110,11 +110,7 @@ int uterm_fbdev_display_blit(struct uterm_display *disp,
        uint32_t val;
        struct fbdev_display *fbdev = disp->data;
 
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
-       if (!buf || !video_is_awake(disp->video))
-               return -EINVAL;
-       if (buf->format != UTERM_FORMAT_XRGB32)
+       if (!buf || buf->format != UTERM_FORMAT_XRGB32)
                return -EINVAL;
 
        tmp = x + buf->width;
@@ -182,9 +178,7 @@ int uterm_fbdev_display_fake_blendv(struct uterm_display *disp,
        uint32_t val;
        struct fbdev_display *fbdev = disp->data;
 
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
-       if (!req || !video_is_awake(disp->video))
+       if (!req)
                return -EINVAL;
 
        for (j = 0; j < num; ++j, ++req) {
@@ -325,11 +319,6 @@ int uterm_fbdev_display_fill(struct uterm_display *disp,
        uint32_t full_val, rgb32;
        struct fbdev_display *fbdev = disp->data;
 
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
-       if (!video_is_awake(disp->video))
-               return -EINVAL;
-
        tmp = x + width;
        if (tmp < x || x >= fbdev->xres)
                return -EINVAL;
index 59e9db6..df5649f 100644 (file)
@@ -88,18 +88,37 @@ static const struct mode_ops fbdev_mode_ops = {
        .get_height = mode_get_height,
 };
 
+static int display_init(struct uterm_display *disp)
+{
+       struct fbdev_display *fbdev;
+
+       fbdev = malloc(sizeof(*fbdev));
+       if (!fbdev)
+               return -ENOMEM;
+       memset(fbdev, 0, sizeof(*fbdev));
+       disp->data = fbdev;
+       disp->dpms = UTERM_DPMS_UNKNOWN;
+
+       return 0;
+}
+
+static void display_destroy(struct uterm_display *disp)
+{
+       free(disp->data);
+}
+
 static int refresh_info(struct uterm_display *disp)
 {
        int ret;
-       struct fbdev_display *fbdev = disp->data;
+       struct fbdev_display *dfb = disp->data;
 
-       ret = ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->finfo);
+       ret = ioctl(dfb->fd, FBIOGET_FSCREENINFO, &dfb->finfo);
        if (ret) {
                log_err("cannot get finfo (%d): %m", errno);
                return -EFAULT;
        }
 
-       ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->vinfo);
+       ret = ioctl(dfb->fd, FBIOGET_VSCREENINFO, &dfb->vinfo);
        if (ret) {
                log_err("cannot get vinfo (%d): %m", errno);
                return -EFAULT;
@@ -115,18 +134,16 @@ static int display_activate_force(struct uterm_display *disp,
        /* TODO: Add support for 24-bpp. However, we need to check how 3-bytes
         * integers are assembled in big/little/mixed endian systems. */
        static const char depths[] = { 32, 16, 0 };
+       struct fbdev_display *dfb = disp->data;
+       struct uterm_mode *m;
+       struct fbdev_mode *mfb;
        struct fb_var_screeninfo *vinfo;
        struct fb_fix_screeninfo *finfo;
        int ret, i;
        uint64_t quot;
        size_t len;
        unsigned int val;
-       struct fbdev_display *fbdev = disp->data;
-       struct fbdev_mode *fbdev_mode;
-       struct uterm_mode *m;
 
-       if (!disp->video || !video_is_awake(disp->video))
-               return -EINVAL;
        if (!force && (disp->flags & DISPLAY_ONLINE))
                return 0;
 
@@ -137,12 +154,18 @@ static int display_activate_force(struct uterm_display *disp,
        if (mode)
                return -EINVAL;
 
+       dfb->fd = open(dfb->node, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+       if (dfb->fd < 0) {
+               log_err("cannot open %s (%d): %m", dfb->node, errno);
+               return -EFAULT;
+       }
+
        ret = refresh_info(disp);
        if (ret)
-               return ret;
+               goto err_close;
 
-       finfo = &fbdev->finfo;
-       vinfo = &fbdev->vinfo;
+       finfo = &dfb->finfo;
+       vinfo = &dfb->vinfo;
 
        vinfo->xoffset = 0;
        vinfo->yoffset = 0;
@@ -165,25 +188,25 @@ static int display_activate_force(struct uterm_display *disp,
                vinfo->yres_virtual = vinfo->yres;
        }
 
-       ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, vinfo);
+       ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO, vinfo);
        if (ret) {
                disp->flags &= ~DISPLAY_DBUF;
                vinfo->yres_virtual = vinfo->yres;
-               ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, vinfo);
+               ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO, vinfo);
                if (ret) {
                        log_debug("cannot reset fb offsets (%d): %m", errno);
-                       return -EFAULT;
+                       goto err_close;
                }
        }
 
        if (disp->flags & DISPLAY_DBUF)
-               log_debug("enabling double buffering");
+               log_debug("enable double buffering");
        else
-               log_debug("disabling double buffering");
+               log_debug("disable double buffering");
 
        ret = refresh_info(disp);
        if (ret)
-               return ret;
+               goto err_close;
 
        /* We require TRUECOLOR mode here. That is, each pixel has a color value
         * that is split into rgba values that we can set directly. Other visual
@@ -196,51 +219,54 @@ static int display_activate_force(struct uterm_display *disp,
                        vinfo->bits_per_pixel = depths[i];
                        vinfo->activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
 
-                       ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO,
+                       ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO,
                                    vinfo);
                        if (ret < 0)
                                continue;
 
                        ret = refresh_info(disp);
                        if (ret)
-                               return ret;
+                               goto err_close;
 
                        if (finfo->visual == FB_VISUAL_TRUECOLOR)
                                break;
                }
        }
 
+       if (vinfo->bits_per_pixel != 32 &&
+           vinfo->bits_per_pixel != 16) {
+               log_error("device %s does not support 16/32 bpp but: %u",
+                         dfb->node, vinfo->bits_per_pixel);
+               ret = -EFAULT;
+               goto err_close;
+       }
+
        if (vinfo->xres_virtual < vinfo->xres ||
            (disp->flags & DISPLAY_DBUF &&
             vinfo->yres_virtual < vinfo->yres * 2) ||
            vinfo->yres_virtual < vinfo->yres) {
                log_warning("device %s has weird virtual buffer sizes (%d %d %d %d)",
-                           fbdev->node, vinfo->xres, vinfo->xres_virtual,
+                           dfb->node, vinfo->xres, vinfo->xres_virtual,
                            vinfo->yres, vinfo->yres_virtual);
        }
 
-       if (vinfo->bits_per_pixel != 32 &&
-           vinfo->bits_per_pixel != 16) {
-               log_error("device %s does not support 16/32 bpp but: %u",
-                         fbdev->node, vinfo->bits_per_pixel);
-               return -EFAULT;
-       }
-
        if (finfo->visual != FB_VISUAL_TRUECOLOR) {
                log_error("device %s does not support true-color",
-                         fbdev->node);
-               return -EFAULT;
+                         dfb->node);
+               ret = -EFAULT;
+               goto err_close;
        }
 
        if (vinfo->red.length > 8 ||
            vinfo->green.length > 8 ||
            vinfo->blue.length > 8) {
                log_error("device %s uses unusual color-ranges",
-                         fbdev->node);
-               return -EFAULT;
+                         dfb->node);
+               ret = -EFAULT;
+               goto err_close;
        }
 
-       log_info("activating display %s to %ux%u %u bpp", fbdev->node,
+       log_info("activating display %s to %ux%u %u bpp", dfb->node,
                 vinfo->xres, vinfo->yres, vinfo->bits_per_pixel);
 
        /* calculate monitor rate, default is 60 Hz */
@@ -248,84 +274,90 @@ static int display_activate_force(struct uterm_display *disp,
        quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
        quot *= vinfo->pixclock;
        if (quot) {
-               fbdev->rate = 1000000000000000LLU / quot;
+               dfb->rate = 1000000000000000LLU / quot;
        } else {
-               fbdev->rate = 60 * 1000;
+               dfb->rate = 60 * 1000;
                log_warning("cannot read monitor refresh rate, forcing 60 Hz");
        }
 
-       if (fbdev->rate == 0) {
+       if (dfb->rate == 0) {
                log_warning("monitor refresh rate is 0 Hz, forcing it to 1 Hz");
-               fbdev->rate = 1;
-       } else if (fbdev->rate > 200000) {
+               dfb->rate = 1;
+       } else if (dfb->rate > 200000) {
                log_warning("monitor refresh rate is >200 Hz (%u Hz), forcing it to 200 Hz",
-                           fbdev->rate / 1000);
-               fbdev->rate = 200000;
+                           dfb->rate / 1000);
+               dfb->rate = 200000;
        }
 
-       val = 1000000 / fbdev->rate;
+       val = 1000000 / dfb->rate;
        display_set_vblank_timer(disp, val);
        log_debug("vblank timer: %u ms, monitor refresh rate: %u Hz", val,
-                 fbdev->rate / 1000);
+                 dfb->rate / 1000);
 
        len = finfo->line_length * vinfo->yres;
        if (disp->flags & DISPLAY_DBUF)
                len *= 2;
 
-       fbdev->map = mmap(0, len, PROT_WRITE, MAP_SHARED,
-                              fbdev->fd, 0);
-       if (fbdev->map == MAP_FAILED) {
-               log_error("cannot mmap device %s (%d): %m", fbdev->node,
+       dfb->map = mmap(0, len, PROT_WRITE, MAP_SHARED, dfb->fd, 0);
+       if (dfb->map == MAP_FAILED) {
+               log_error("cannot mmap device %s (%d): %m", dfb->node,
                          errno);
-               return -EFAULT;
+               ret = -EFAULT;
+               goto err_close;
        }
 
-       memset(fbdev->map, 0, len);
-       fbdev->xres = vinfo->xres;
-       fbdev->yres = vinfo->yres;
-       fbdev->len = len;
-       fbdev->stride = finfo->line_length;
-       fbdev->bufid = 0;
-       fbdev->Bpp = vinfo->bits_per_pixel / 8;
-       fbdev->off_r = vinfo->red.offset;
-       fbdev->len_r = vinfo->red.length;
-       fbdev->off_g = vinfo->green.offset;
-       fbdev->len_g = vinfo->green.length;
-       fbdev->off_b = vinfo->blue.offset;
-       fbdev->len_b = vinfo->blue.length;
-       fbdev->dither_r = 0;
-       fbdev->dither_g = 0;
-       fbdev->dither_b = 0;
-       fbdev->xrgb32 = false;
-       if (fbdev->len_r == 8 &&
-           fbdev->len_g == 8 &&
-           fbdev->len_b == 8 &&
-           fbdev->off_r == 16 &&
-           fbdev->off_g ==  8 &&
-           fbdev->off_b ==  0 &&
-           fbdev->Bpp == 4)
-               fbdev->xrgb32 = true;
+       memset(dfb->map, 0, len);
+       dfb->xres = vinfo->xres;
+       dfb->yres = vinfo->yres;
+       dfb->len = len;
+       dfb->stride = finfo->line_length;
+       dfb->bufid = 0;
+       dfb->Bpp = vinfo->bits_per_pixel / 8;
+       dfb->off_r = vinfo->red.offset;
+       dfb->len_r = vinfo->red.length;
+       dfb->off_g = vinfo->green.offset;
+       dfb->len_g = vinfo->green.length;
+       dfb->off_b = vinfo->blue.offset;
+       dfb->len_b = vinfo->blue.length;
+       dfb->dither_r = 0;
+       dfb->dither_g = 0;
+       dfb->dither_b = 0;
+       dfb->xrgb32 = false;
+       if (dfb->len_r == 8 && dfb->len_g == 8 && dfb->len_b == 8 &&
+           dfb->off_r == 16 && dfb->off_g ==  8 && dfb->off_b ==  0 &&
+           dfb->Bpp == 4)
+               dfb->xrgb32 = true;
 
        /* TODO: make dithering configurable */
        disp->flags |= DISPLAY_DITHERING;
 
-       if (!disp->current_mode) {
+       if (disp->current_mode) {
+               m = disp->current_mode;
+       } else {
                ret = mode_new(&m, &fbdev_mode_ops);
+               if (ret)
+                       goto err_map;
+               ret = uterm_mode_bind(m, disp);
                if (ret) {
-                       munmap(fbdev->map, fbdev->len);
-                       return ret;
+                       uterm_mode_unref(m);
+                       goto err_map;
                }
-               m->next = disp->modes;
-               disp->modes = m;
-
-               fbdev_mode = m->data;
-               fbdev_mode->width = fbdev->xres;
-               fbdev_mode->height = fbdev->yres;
-               disp->current_mode = disp->modes;
+               disp->current_mode = m;
+               uterm_mode_unref(m);
        }
 
+       mfb = m->data;
+       mfb->width = dfb->xres;
+       mfb->height = dfb->yres;
+
        disp->flags |= DISPLAY_ONLINE;
        return 0;
+
+err_map:
+       munmap(dfb->map, dfb->len);
+err_close:
+       close(dfb->fd);
+       return ret;
 }
 
 static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
@@ -335,23 +367,21 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
 
 static void display_deactivate_force(struct uterm_display *disp, bool force)
 {
-       struct fbdev_display *fbdev = disp->data;
+       struct fbdev_display *dfb = disp->data;
 
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return;
-
-       log_info("deactivating device %s", fbdev->node);
+       log_info("deactivating device %s", dfb->node);
 
+       if (dfb->map) {
+               memset(dfb->map, 0, dfb->len);
+               munmap(dfb->map, dfb->len);
+               close(dfb->fd);
+               dfb->map = NULL;
+       }
        if (!force) {
-               uterm_mode_unref(disp->current_mode);
-               disp->modes = NULL;
+               uterm_mode_unbind(disp->current_mode);
                disp->current_mode = NULL;
-       }
-       memset(fbdev->map, 0, fbdev->len);
-       munmap(fbdev->map, fbdev->len);
-
-       if (!force)
                disp->flags &= ~DISPLAY_ONLINE;
+       }
 }
 
 static void display_deactivate(struct uterm_display *disp)
@@ -362,10 +392,7 @@ static void display_deactivate(struct uterm_display *disp)
 static int display_set_dpms(struct uterm_display *disp, int state)
 {
        int set, ret;
-       struct fbdev_display *fbdev = disp->data;
-
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
+       struct fbdev_display *dfb = disp->data;
 
        switch (state) {
        case UTERM_DPMS_ON:
@@ -384,12 +411,12 @@ static int display_set_dpms(struct uterm_display *disp, int state)
                return -EINVAL;
        }
 
-       log_info("setting DPMS of device %p to %s", fbdev->node,
+       log_info("setting DPMS of device %p to %s", dfb->node,
                 uterm_dpms_to_name(state));
 
-       ret = ioctl(fbdev->fd, FBIOBLANK, set);
+       ret = ioctl(dfb->fd, FBIOBLANK, set);
        if (ret) {
-               log_error("cannot set DPMS on %s (%d): %m", fbdev->node,
+               log_error("cannot set DPMS on %s (%d): %m", dfb->node,
                          errno);
                return -EFAULT;
        }
@@ -400,41 +427,35 @@ static int display_set_dpms(struct uterm_display *disp, int state)
 
 static int display_swap(struct uterm_display *disp)
 {
+       struct fbdev_display *dfb = disp->data;
        struct fb_var_screeninfo *vinfo;
        int ret;
-       struct fbdev_display *fbdev = disp->data;
-
-       if (!disp->video || !video_is_awake(disp->video))
-               return -EINVAL;
-       if (!(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
 
-       if (!(disp->flags & DISPLAY_DBUF)) {
+       if (!(disp->flags & DISPLAY_DBUF))
                return display_schedule_vblank_timer(disp);
-       }
 
-       vinfo = &fbdev->vinfo;
+       vinfo = &dfb->vinfo;
        vinfo->activate = FB_ACTIVATE_VBL;
 
-       if (!fbdev->bufid)
-               vinfo->yoffset = fbdev->yres;
+       if (!dfb->bufid)
+               vinfo->yoffset = dfb->yres;
        else
                vinfo->yoffset = 0;
 
-       ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, vinfo);
+       ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO, vinfo);
        if (ret) {
                log_warning("cannot swap buffers on %s (%d): %m",
-                           fbdev->node, errno);
+                           dfb->node, errno);
                return -EFAULT;
        }
 
-       fbdev->bufid ^= 1;
+       dfb->bufid ^= 1;
        return display_schedule_vblank_timer(disp);
 }
 
 static const struct display_ops fbdev_display_ops = {
-       .init = NULL,
-       .destroy = NULL,
+       .init = display_init,
+       .destroy = display_destroy,
        .activate = display_activate,
        .deactivate = display_deactivate,
        .set_dpms = display_set_dpms,
@@ -447,120 +468,100 @@ static const struct display_ops fbdev_display_ops = {
 
 static void intro_idle_event(struct ev_eloop *eloop, void *unused, void *data)
 {
-       struct uterm_display *disp = data;
-       struct fbdev_display *fbdev = disp->data;
+       struct uterm_video *video = data;
+       struct fbdev_video *vfb = video->data;
+       struct uterm_display *disp;
+       struct fbdev_display *dfb;
+       int ret;
 
-       if (!fbdev->pending_intro)
-               return;
+       vfb->pending_intro = false;
+       ev_eloop_unregister_idle_cb(eloop, intro_idle_event, data);
 
-       fbdev->pending_intro = false;
-       ev_eloop_unregister_idle_cb(eloop, intro_idle_event, disp);
+       ret = display_new(&disp, &fbdev_display_ops);
+       if (ret) {
+               log_error("cannot create fbdev display: %d", ret);
+               return;
+       }
 
-       if (!disp->video)
+       dfb = disp->data;
+       dfb->node = vfb->node;
+       ret = uterm_display_bind(disp, video);
+       if (ret) {
+               log_error("cannot bind fbdev display: %d", ret);
+               uterm_display_unref(disp);
                return;
+       }
 
-       VIDEO_CB(disp->video, disp, UTERM_NEW);
+       uterm_display_unref(disp);
 }
 
 static int video_init(struct uterm_video *video, const char *node)
 {
        int ret;
-       struct uterm_display *disp;
-       struct fbdev_display *fbdev;
-
-       fbdev = malloc(sizeof(*fbdev));
-       if (!fbdev)
-               return -ENOMEM;
-       memset(fbdev, 0, sizeof(*fbdev));
+       struct fbdev_video *vfb;
 
-       ret = display_new(&disp, &fbdev_display_ops, video);
-       if (ret)
-               goto err_fbdev;
-       disp->data = fbdev;
+       log_info("new device on %s", node);
 
-       ret = ev_eloop_register_idle_cb(video->eloop, intro_idle_event, disp);
-       if (ret) {
-               log_error("cannot register idle event: %d", ret);
-               goto err_free;
-       }
-       fbdev->pending_intro = true;
+       vfb = malloc(sizeof(*vfb));
+       if (!vfb)
+               return -ENOMEM;
+       memset(vfb, 0, sizeof(*vfb));
+       video->data = vfb;
 
-       fbdev->node = strdup(node);
-       if (!fbdev->node) {
-               log_err("cannot dup node name");
+       vfb->node = strdup(node);
+       if (!vfb->node) {
                ret = -ENOMEM;
-               goto err_idle;
+               goto err_free;
        }
 
-       fbdev->fd = open(node, O_RDWR | O_CLOEXEC);
-       if (fbdev->fd < 0) {
-               log_err("cannot open %s (%d): %m", node, errno);
-               ret = -EFAULT;
+       ret = ev_eloop_register_idle_cb(video->eloop, intro_idle_event, video);
+       if (ret) {
+               log_error("cannot register idle event: %d", ret);
                goto err_node;
        }
+       vfb->pending_intro = true;
 
-       disp->dpms = UTERM_DPMS_UNKNOWN;
-       video->displays = disp;
-
-       log_info("new device on %s", fbdev->node);
        return 0;
 
 err_node:
-       free(fbdev->node);
-err_idle:
-       ev_eloop_register_idle_cb(video->eloop, intro_idle_event, disp);
+       free(vfb->node);
 err_free:
-       uterm_display_unref(disp);
-err_fbdev:
-       free(fbdev);
+       free(vfb);
        return ret;
 }
 
 static void video_destroy(struct uterm_video *video)
 {
-       struct uterm_display *disp;
-       struct fbdev_display *fbdev;
+       struct fbdev_video *vfb = video->data;
 
-       log_info("free device %p", video);
-       disp = video->displays;
-       video->displays = disp->next;
-       fbdev = disp->data;
+       log_info("free device on %s", vfb->node);
 
-       if (fbdev->pending_intro)
+       if (vfb->pending_intro)
                ev_eloop_unregister_idle_cb(video->eloop, intro_idle_event,
-                                           disp);
-       else
-               VIDEO_CB(video, disp, UTERM_GONE);
+                                           video);
 
-       close(fbdev->fd);
-       free(fbdev->node);
-       free(fbdev);
-       uterm_display_unref(disp);
+       free(vfb->node);
+       free(vfb);
 }
 
 static void video_sleep(struct uterm_video *video)
 {
-       if (!(video->flags & VIDEO_AWAKE))
-               return;
+       struct fbdev_video *vfb = video->data;
 
-       display_deactivate_force(video->displays, true);
-       video->flags &= ~VIDEO_AWAKE;
+       if (vfb->disp && display_is_online(vfb->disp))
+               display_deactivate_force(vfb->disp, true);
 }
 
 static int video_wake_up(struct uterm_video *video)
 {
+       struct fbdev_video *vfb = video->data;
        int ret;
 
-       if (video->flags & VIDEO_AWAKE)
-               return 0;
-
-       video->flags |= VIDEO_AWAKE;
-       if (video->displays->flags & DISPLAY_ONLINE) {
-               ret = display_activate_force(video->displays, NULL, true);
-               if (ret) {
-                       video->flags &= ~VIDEO_AWAKE;
+       if (vfb->disp && display_is_online(vfb->disp)) {
+               video->flags |= VIDEO_AWAKE;
+               ret = display_activate_force(vfb->disp, NULL, true);
+               if (ret)
                        return ret;
-               }
        }
 
        return 0;
index 78cf661..aed5e44 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * uterm - Linux User-Space Terminal
  *
- * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
+ * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
@@ -36,6 +36,7 @@
 #include <unistd.h>
 #include "eloop.h"
 #include "log.h"
+#include "shl_dlist.h"
 #include "shl_hook.h"
 #include "uterm_video.h"
 #include "uterm_video_internal.h"
@@ -113,12 +114,34 @@ void uterm_mode_unref(struct uterm_mode *mode)
        free(mode);
 }
 
-struct uterm_mode *uterm_mode_next(struct uterm_mode *mode)
+int uterm_mode_bind(struct uterm_mode *mode, struct uterm_display *disp)
+{
+       if (!mode || !disp || mode->disp)
+               return -EINVAL;
+
+       mode->disp = disp;
+       shl_dlist_link_tail(&disp->modes, &mode->list);
+       uterm_mode_ref(mode);
+
+       return 0;
+}
+
+void uterm_mode_unbind(struct uterm_mode *mode)
 {
        if (!mode)
+               return;
+
+       mode->disp = NULL;
+       shl_dlist_unlink(&mode->list);
+       uterm_mode_unref(mode);
+}
+
+struct uterm_mode *uterm_mode_next(struct uterm_mode *mode)
+{
+       if (!mode || mode->list.next == &mode->disp->modes)
                return NULL;
 
-       return mode->next;
+       return shl_dlist_entry(mode->list.next, struct uterm_mode, list);
 }
 
 const char *uterm_mode_get_name(const struct uterm_mode *mode)
@@ -181,13 +204,12 @@ static void display_vblank_timer_event(struct ev_timer *timer,
        DISPLAY_CB(disp, UTERM_PAGE_FLIP);
 }
 
-int display_new(struct uterm_display **out, const struct display_ops *ops,
-               struct uterm_video *video)
+int display_new(struct uterm_display **out, const struct display_ops *ops)
 {
        struct uterm_display *disp;
        int ret;
 
-       if (!out || !ops || !video)
+       if (!out || !ops)
                return -EINVAL;
 
        disp = malloc(sizeof(*disp));
@@ -196,7 +218,9 @@ int display_new(struct uterm_display **out, const struct display_ops *ops,
        memset(disp, 0, sizeof(*disp));
        disp->ref = 1;
        disp->ops = ops;
-       disp->video = video;
+       shl_dlist_init(&disp->modes);
+
+       log_info("new display %p", disp);
 
        ret = shl_hook_new(&disp->hook);
        if (ret)
@@ -209,20 +233,13 @@ int display_new(struct uterm_display **out, const struct display_ops *ops,
        if (ret)
                goto err_hook;
 
-       ret = ev_eloop_add_timer(video->eloop, disp->vblank_timer);
-       if (ret)
-               goto err_timer;
-
        ret = VIDEO_CALL(disp->ops->init, 0, disp);
        if (ret)
-               goto err_eloop_timer;
+               goto err_timer;
 
-       log_info("new display %p", disp);
        *out = disp;
        return 0;
 
-err_eloop_timer:
-       ev_eloop_rm_timer(disp->vblank_timer);
 err_timer:
        ev_timer_unref(disp->vblank_timer);
 err_hook:
@@ -249,25 +266,56 @@ void uterm_display_unref(struct uterm_display *disp)
 
        log_info("free display %p", disp);
 
-       VIDEO_CALL(disp->ops->destroy, 0, disp);
-
-       while ((mode = disp->modes)) {
-               disp->modes = mode->next;
-               mode->next = NULL;
-               uterm_mode_unref(mode);
+       while (!shl_dlist_empty(&disp->modes)) {
+               mode = shl_dlist_entry(disp->modes.prev, struct uterm_mode,
+                                      list);
+               uterm_mode_unbind(mode);
        }
-       ev_eloop_rm_timer(disp->vblank_timer);
+
+       VIDEO_CALL(disp->ops->destroy, 0, disp);
        ev_timer_unref(disp->vblank_timer);
        shl_hook_free(disp->hook);
        free(disp);
 }
 
+int uterm_display_bind(struct uterm_display *disp, struct uterm_video *video)
+{
+       int ret;
+
+       if (!disp || !video || disp->video)
+               return -EINVAL;
+
+       ret = ev_eloop_add_timer(video->eloop, disp->vblank_timer);
+       if (ret)
+               return ret;
+
+       shl_dlist_link_tail(&video->displays, &disp->list);
+       disp->video = video;
+       uterm_display_ref(disp);
+       VIDEO_CB(disp->video, disp, UTERM_NEW);
+
+       return 0;
+}
+
+void uterm_display_unbind(struct uterm_display *disp)
+{
+       if (!disp || !disp->video)
+               return;
+
+       VIDEO_CB(disp->video, disp, UTERM_GONE);
+       uterm_display_deactivate(disp);
+       disp->video = NULL;
+       shl_dlist_unlink(&disp->list);
+       ev_eloop_rm_timer(disp->vblank_timer);
+       uterm_display_unref(disp);
+}
+
 struct uterm_display *uterm_display_next(struct uterm_display *disp)
 {
-       if (!disp)
+       if (!disp || !disp->video || disp->list.next == &disp->video->displays)
                return NULL;
 
-       return disp->next;
+       return shl_dlist_entry(disp->list.next, struct uterm_display, list);
 }
 
 int uterm_display_register_cb(struct uterm_display *disp, uterm_display_cb cb,
@@ -290,10 +338,10 @@ void uterm_display_unregister_cb(struct uterm_display *disp,
 
 struct uterm_mode *uterm_display_get_modes(struct uterm_display *disp)
 {
-       if (!disp)
+       if (!disp || shl_dlist_empty(&disp->modes))
                return NULL;
 
-       return disp->modes;
+       return shl_dlist_entry(disp->modes.next, struct uterm_mode, list);
 }
 
 struct uterm_mode *uterm_display_get_current(struct uterm_display *disp)
@@ -333,7 +381,8 @@ int uterm_display_get_state(struct uterm_display *disp)
 
 int uterm_display_activate(struct uterm_display *disp, struct uterm_mode *mode)
 {
-       if (!disp || !display_is_conn(disp) || display_is_online(disp))
+       if (!disp || !disp->video || display_is_online(disp) ||
+           !video_is_awake(disp->video))
                return -EINVAL;
 
        if (!mode)
@@ -352,7 +401,7 @@ void uterm_display_deactivate(struct uterm_display *disp)
 
 int uterm_display_set_dpms(struct uterm_display *disp, int state)
 {
-       if (!disp || !display_is_conn(disp))
+       if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
                return -EINVAL;
 
        return VIDEO_CALL(disp->ops->set_dpms, 0, disp, state);
@@ -360,7 +409,7 @@ int uterm_display_set_dpms(struct uterm_display *disp, int state)
 
 int uterm_display_get_dpms(const struct uterm_display *disp)
 {
-       if (!disp || !display_is_conn(disp))
+       if (!disp || !disp->video)
                return UTERM_DPMS_OFF;
 
        return disp->dpms;
@@ -376,7 +425,7 @@ int uterm_display_use(struct uterm_display *disp)
 
 int uterm_display_swap(struct uterm_display *disp)
 {
-       if (!disp || !display_is_online(disp))
+       if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
                return -EINVAL;
 
        return VIDEO_CALL(disp->ops->swap, 0, disp);
@@ -395,7 +444,7 @@ int uterm_display_fill(struct uterm_display *disp,
                       unsigned int x, unsigned int y,
                       unsigned int width, unsigned int height)
 {
-       if (!disp)
+       if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
                return -EINVAL;
 
        return VIDEO_CALL(disp->ops->fill, -EOPNOTSUPP, disp, r, g, b, x, y,
@@ -406,7 +455,7 @@ int uterm_display_blit(struct uterm_display *disp,
                       const struct uterm_video_buffer *buf,
                       unsigned int x, unsigned int y)
 {
-       if (!disp)
+       if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
                return -EINVAL;
 
        return VIDEO_CALL(disp->ops->blit, -EOPNOTSUPP, disp, buf, x, y);
@@ -420,7 +469,7 @@ int uterm_display_fake_blend(struct uterm_display *disp,
 {
        struct uterm_video_blend_req req;
 
-       if (!disp)
+       if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
                return -EINVAL;
 
        memset(&req, 0, sizeof(req));
@@ -441,7 +490,7 @@ int uterm_display_fake_blendv(struct uterm_display *disp,
                              const struct uterm_video_blend_req *req,
                              size_t num)
 {
-       if (!disp)
+       if (!disp || !display_is_online(disp) || !video_is_awake(disp->video))
                return -EINVAL;
 
        return VIDEO_CALL(disp->ops->fake_blendv, -EOPNOTSUPP, disp, req, num);
@@ -466,6 +515,7 @@ int uterm_video_new(struct uterm_video **out, struct ev_eloop *eloop,
        video->mod = mod;
        video->ops = mod->ops;
        video->eloop = eloop;
+       shl_dlist_init(&video->displays);
 
        ret = shl_hook_new(&video->hook);
        if (ret)
@@ -504,14 +554,13 @@ void uterm_video_unref(struct uterm_video *video)
 
        log_info("free device %p", video);
 
-       VIDEO_CALL(video->ops->destroy, 0, video);
-
-       while ((disp = video->displays)) {
-               video->displays = disp->next;
-               disp->next = NULL;
-               uterm_display_unref(disp);
+       while (!shl_dlist_empty(&video->displays)) {
+               disp = shl_dlist_entry(video->displays.prev,
+                                      struct uterm_display, list);
+               uterm_display_unbind(disp);
        }
 
+       VIDEO_CALL(video->ops->destroy, 0, video);
        shl_hook_free(video->hook);
        ev_eloop_unref(video->eloop);
        free(video);
@@ -535,10 +584,11 @@ int uterm_video_use(struct uterm_video *video)
 
 struct uterm_display *uterm_video_get_displays(struct uterm_video *video)
 {
-       if (!video)
+       if (!video || shl_dlist_empty(&video->displays))
                return NULL;
 
-       return video->displays;
+       return shl_dlist_entry(video->displays.next, struct uterm_display,
+                              list);
 }
 
 int uterm_video_register_cb(struct uterm_video *video, uterm_video_cb cb,
@@ -565,6 +615,7 @@ void uterm_video_sleep(struct uterm_video *video)
                return;
 
        VIDEO_CB(video, NULL, UTERM_SLEEP);
+       video->flags &= ~VIDEO_AWAKE;
        VIDEO_CALL(video->ops->sleep, 0, video);
 }
 
@@ -578,9 +629,12 @@ int uterm_video_wake_up(struct uterm_video *video)
                return 0;
 
        ret = VIDEO_CALL(video->ops->wake_up, 0, video);
-       if (ret)
+       if (ret) {
+               video->flags &= ~VIDEO_AWAKE;
                return ret;
+       }
 
+       video->flags |= VIDEO_AWAKE;
        VIDEO_CB(video, NULL, UTERM_WAKE_UP);
        return 0;
 }
index d781a16..4e44aab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * uterm - Linux User-Space Terminal
  *
- * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
+ * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
@@ -183,9 +183,7 @@ static int display_activate(struct uterm_display *disp,
        struct gbm_bo *bo;
        drmModeModeInfo *minfo;
 
-       if (!video || !video_is_awake(video) || !mode)
-               return -EINVAL;
-       if (display_is_online(disp))
+       if (!mode)
                return -EINVAL;
 
        vdrm = video->data;
@@ -283,9 +281,6 @@ static void display_deactivate(struct uterm_display *disp)
        struct uterm_drm_video *vdrm;
        struct uterm_drm3d_video *v3d;
 
-       if (!display_is_online(disp))
-               return;
-
        log_info("deactivating display %p", disp);
 
        vdrm = video->data;
@@ -317,9 +312,6 @@ static int display_use(struct uterm_display *disp)
        struct uterm_drm3d_display *d3d = uterm_drm_display_get_data(disp);
        struct uterm_drm3d_video *v3d;
 
-       if (!display_is_online(disp))
-               return -EINVAL;
-
        v3d = uterm_drm_video_get_data(disp->video);
        if (!eglMakeCurrent(v3d->disp, d3d->surface,
                            d3d->surface, v3d->ctx)) {
@@ -340,8 +332,6 @@ static int swap_display(struct uterm_display *disp, bool immediate)
        struct uterm_drm3d_video *v3d;
        struct uterm_drm_video *vdrm;
 
-       if (!display_is_online(disp) || !video_is_awake(disp->video))
-               return -EINVAL;
        if (disp->dpms != UTERM_DPMS_ON)
                return -EINVAL;
        if (!immediate &&
@@ -528,11 +518,7 @@ static int display_blit(struct uterm_display *disp,
        int ret;
        uint8_t *packed, *src, *dst;
 
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
-       if (!video_is_awake(disp->video))
-               return -EINVAL;
-       if (buf->format != UTERM_FORMAT_XRGB32)
+       if (!buf || buf->format != UTERM_FORMAT_XRGB32)
                return -EINVAL;
 
        v3d = uterm_drm_video_get_data(disp->video);
@@ -661,11 +647,7 @@ static int display_blend(struct uterm_display *disp,
        int ret;
        uint8_t *packed, *src, *dst;
 
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
-       if (!video_is_awake(disp->video))
-               return -EINVAL;
-       if (buf->format != UTERM_FORMAT_GREY)
+       if (!buf || buf->format != UTERM_FORMAT_GREY)
                return -EINVAL;
 
        v3d = uterm_drm_video_get_data(disp->video);
@@ -826,11 +808,6 @@ static int display_fill(struct uterm_display *disp,
        float vertices[6 * 2], colors[6 * 4];
        int ret;
 
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
-       if (!video_is_awake(disp->video))
-               return -EINVAL;
-
        v3d = uterm_drm_video_get_data(disp->video);
        ret = display_use(disp);
        if (ret)
@@ -913,11 +890,14 @@ static void show_displays(struct uterm_video *video)
 {
        int ret;
        struct uterm_display *iter;
+       struct shl_dlist *i;
 
        if (!video_is_awake(video))
                return;
 
-       for (iter = video->displays; iter; iter = iter->next) {
+       shl_dlist_for_each(i, &video->displays) {
+               iter = shl_dlist_entry(i, struct uterm_display, list);
+
                if (!display_is_online(iter))
                        continue;
                if (iter->dpms != UTERM_DPMS_ON)
@@ -989,6 +969,8 @@ static int video_init(struct uterm_video *video, const char *node)
                goto err_free;
        vdrm = video->data;
 
+       log_debug("initialize 3D layer on %p", video);
+
        v3d->gbm = gbm_create_device(vdrm->fd);
        if (!v3d->gbm) {
                log_err("cannot create gbm device for %s (permission denied)",
@@ -1076,17 +1058,9 @@ err_free:
 static void video_destroy(struct uterm_video *video)
 {
        struct uterm_drm3d_video *v3d = uterm_drm_video_get_data(video);
-       struct uterm_display *disp;
 
        log_info("free drm video device %p", video);
 
-       while ((disp = video->displays)) {
-               video->displays = disp->next;
-               disp->next = NULL;
-               uterm_drm_display_unbind(disp);
-               uterm_display_unref(disp);
-       }
-
        if (!eglMakeCurrent(v3d->disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
                            v3d->ctx))
                log_error("cannot activate GL context during destruction");
index 1b7aff3..63dffb0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * uterm - Linux User-Space Terminal
  *
- * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
+ * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
@@ -181,9 +181,7 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
        int ret;
        drmModeModeInfo *minfo;
 
-       if (!video || !video_is_awake(video) || !mode)
-               return -EINVAL;
-       if (display_is_online(disp))
+       if (!mode)
                return -EINVAL;
 
        minfo = uterm_drm_mode_get_info(mode);;
@@ -232,9 +230,6 @@ static void display_deactivate(struct uterm_display *disp)
        struct uterm_drm_video *vdrm;
        struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
 
-       if (!display_is_online(disp))
-               return;
-
        vdrm = disp->video->data;
        log_info("deactivating display %p", disp);
 
@@ -253,8 +248,6 @@ static int display_swap(struct uterm_display *disp)
        struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
        struct uterm_drm_video *vdrm;
 
-       if (!display_is_online(disp) || !video_is_awake(disp->video))
-               return -EINVAL;
        if (disp->dpms != UTERM_DPMS_ON)
                return -EINVAL;
 
@@ -285,11 +278,7 @@ static int display_blit(struct uterm_display *disp,
        struct uterm_drm2d_rb *rb;
        struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
 
-       if (!disp->video || !display_is_online(disp))
-               return -EINVAL;
-       if (!buf || !video_is_awake(disp->video))
-               return -EINVAL;
-       if (buf->format != UTERM_FORMAT_XRGB32)
+       if (!buf || buf->format != UTERM_FORMAT_XRGB32)
                return -EINVAL;
 
        rb = &d2d->rb[d2d->current_rb ^ 1];
@@ -337,9 +326,7 @@ static int display_fake_blendv(struct uterm_display *disp,
        struct uterm_drm2d_rb *rb;
        struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
 
-       if (!disp->video || !display_is_online(disp))
-               return -EINVAL;
-       if (!req || !video_is_awake(disp->video))
+       if (!req)
                return -EINVAL;
 
        rb = &d2d->rb[d2d->current_rb ^ 1];
@@ -419,11 +406,6 @@ static int display_fill(struct uterm_display *disp,
        struct uterm_drm2d_rb *rb;
        struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
 
-       if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
-               return -EINVAL;
-       if (!video_is_awake(disp->video))
-               return -EINVAL;
-
        rb = &d2d->rb[d2d->current_rb ^ 1];
        sw = uterm_drm_mode_get_width(disp->current_mode);
        sh = uterm_drm_mode_get_height(disp->current_mode);
@@ -472,11 +454,14 @@ static void show_displays(struct uterm_video *video)
        struct uterm_drm2d_display *d2d;
        struct uterm_drm2d_rb *rb;
        struct uterm_drm_video *vdrm = video->data;
+       struct shl_dlist *i;
 
        if (!video_is_awake(video))
                return;
 
-       for (iter = video->displays; iter; iter = iter->next) {
+       shl_dlist_for_each(i, &video->displays) {
+               iter = shl_dlist_entry(i, struct uterm_display, list);
+
                if (!display_is_online(iter))
                        continue;
                if (iter->dpms != UTERM_DPMS_ON)
@@ -502,11 +487,11 @@ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
 {
        struct uterm_display *disp = data;
 
-       uterm_display_unref(disp);
        if (disp->flags & DISPLAY_VSYNC) {
                disp->flags &= ~DISPLAY_VSYNC;
                DISPLAY_CB(disp, UTERM_PAGE_FLIP);
        }
+       uterm_display_unref(disp);
 }
 
 static int video_init(struct uterm_video *video, const char *node)
@@ -520,6 +505,8 @@ static int video_init(struct uterm_video *video, const char *node)
                return ret;
        vdrm = video->data;
 
+       log_debug("initialize 2D layer on %p", video);
+
        if (drmGetCap(vdrm->fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 ||
            !has_dumb) {
                log_err("driver does not support dumb buffers");
@@ -532,17 +519,7 @@ static int video_init(struct uterm_video *video, const char *node)
 
 static void video_destroy(struct uterm_video *video)
 {
-       struct uterm_display *disp;
-
        log_info("free drm video device %p", video);
-
-       while ((disp = video->displays)) {
-               video->displays = disp->next;
-               disp->next = NULL;
-               uterm_drm_display_unbind(disp);
-               uterm_display_unref(disp);
-       }
-
        uterm_drm_video_destroy(video);
 }
 
index dc92aec..ad627f0 100644 (file)
@@ -33,6 +33,7 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include "eloop.h"
+#include "shl_dlist.h"
 #include "shl_hook.h"
 #include "uterm_video.h"
 
@@ -84,14 +85,17 @@ struct uterm_video_module {
 /* uterm_mode */
 
 struct uterm_mode {
+       struct shl_dlist list;
        unsigned long ref;
-       struct uterm_mode *next;
+       struct uterm_display *disp;
 
        const struct mode_ops *ops;
        void *data;
 };
 
 int mode_new(struct uterm_mode **out, const struct mode_ops *ops);
+int uterm_mode_bind(struct uterm_mode *mode, struct uterm_display *disp);
+void uterm_mode_unbind(struct uterm_mode *mode);
 
 /* uterm_display */
 
@@ -103,13 +107,13 @@ int mode_new(struct uterm_mode **out, const struct mode_ops *ops);
 #define DISPLAY_DITHERING      0x20
 
 struct uterm_display {
+       struct shl_dlist list;
        unsigned long ref;
        unsigned int flags;
-       struct uterm_display *next;
        struct uterm_video *video;
 
        struct shl_hook *hook;
-       struct uterm_mode *modes;
+       struct shl_dlist modes;
        struct uterm_mode *default_mode;
        struct uterm_mode *current_mode;
        int dpms;
@@ -122,25 +126,21 @@ struct uterm_display {
        void *data;
 };
 
-int display_new(struct uterm_display **out, const struct display_ops *ops,
-               struct uterm_video *video);
+int display_new(struct uterm_display **out, const struct display_ops *ops);
 void display_set_vblank_timer(struct uterm_display *disp,
                              unsigned int msecs);
 int display_schedule_vblank_timer(struct uterm_display *disp);
+int uterm_display_bind(struct uterm_display *disp, struct uterm_video *video);
+void uterm_display_unbind(struct uterm_display *disp);
 
 #define DISPLAY_CB(disp, act) shl_hook_call((disp)->hook, (disp), \
                &(struct uterm_display_event){ \
                        .action = (act), \
                })
 
-static inline bool display_is_conn(const struct uterm_display *disp)
-{
-       return disp->video;
-}
-
 static inline bool display_is_online(const struct uterm_display *disp)
 {
-       return display_is_conn(disp) && (disp->flags & DISPLAY_ONLINE);
+       return disp->video && (disp->flags & DISPLAY_ONLINE);
 }
 
 /* uterm_video */
@@ -153,7 +153,7 @@ struct uterm_video {
        unsigned int flags;
        struct ev_eloop *eloop;
 
-       struct uterm_display *displays;
+       struct shl_dlist displays;
        struct shl_hook *hook;
 
        const struct uterm_video_module *mod;