summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/uterm_drm_shared.c156
-rw-r--r--src/uterm_drm_shared_internal.h4
-rw-r--r--src/uterm_fbdev_internal.h10
-rw-r--r--src/uterm_fbdev_render.c15
-rw-r--r--src/uterm_fbdev_video.c373
-rw-r--r--src/uterm_video.c140
-rw-r--r--src/uterm_video_drm.c46
-rw-r--r--src/uterm_video_dumb.c45
-rw-r--r--src/uterm_video_internal.h24
9 files changed, 392 insertions, 421 deletions
diff --git a/src/uterm_drm_shared.c b/src/uterm_drm_shared.c
index 3a55b05..90069de 100644
--- a/src/uterm_drm_shared.c
+++ b/src/uterm_drm_shared.c
@@ -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,
diff --git a/src/uterm_drm_shared_internal.h b/src/uterm_drm_shared_internal.h
index 6b857c2..199d5b3 100644
--- a/src/uterm_drm_shared_internal.h
+++ b/src/uterm_drm_shared_internal.h
@@ -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)
diff --git a/src/uterm_fbdev_internal.h b/src/uterm_fbdev_internal.h
index c4257c7..b0ac72e 100644
--- a/src/uterm_fbdev_internal.h
+++ b/src/uterm_fbdev_internal.h
@@ -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);
diff --git a/src/uterm_fbdev_render.c b/src/uterm_fbdev_render.c
index f441153..ad96ad3 100644
--- a/src/uterm_fbdev_render.c
+++ b/src/uterm_fbdev_render.c
@@ -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;
diff --git a/src/uterm_fbdev_video.c b/src/uterm_fbdev_video.c
index 59e9db6..df5649f 100644
--- a/src/uterm_fbdev_video.c
+++ b/src/uterm_fbdev_video.c
@@ -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;
diff --git a/src/uterm_video.c b/src/uterm_video.c
index 78cf661..aed5e44 100644
--- a/src/uterm_video.c
+++ b/src/uterm_video.c
@@ -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;
}
diff --git a/src/uterm_video_drm.c b/src/uterm_video_drm.c
index d781a16..4e44aab 100644
--- a/src/uterm_video_drm.c
+++ b/src/uterm_video_drm.c
@@ -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");
diff --git a/src/uterm_video_dumb.c b/src/uterm_video_dumb.c
index 1b7aff3..63dffb0 100644
--- a/src/uterm_video_dumb.c
+++ b/src/uterm_video_dumb.c
@@ -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);
}
diff --git a/src/uterm_video_internal.h b/src/uterm_video_internal.h
index dc92aec..ad627f0 100644
--- a/src/uterm_video_internal.h
+++ b/src/uterm_video_internal.h
@@ -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;