diff options
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-ioctl.c')
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 125 |
1 files changed, 102 insertions, 23 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 9c73618..6635bd7 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -34,12 +34,37 @@ #include "omapfb.h" +static u8 get_mem_idx(struct omapfb_info *ofbi) +{ + if (ofbi->id == ofbi->region->id) + return 0; + + return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id; +} + +static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, + u8 mem_idx) +{ + struct omapfb2_device *fbdev = ofbi->fbdev; + + if (mem_idx & OMAPFB_MEM_IDX_ENABLED) + mem_idx &= OMAPFB_MEM_IDX_MASK; + else + mem_idx = ofbi->id; + + if (mem_idx >= fbdev->num_fbs) + return NULL; + + return &fbdev->regions[mem_idx]; +} + static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_overlay *ovl; - struct omap_overlay_info info; + struct omap_overlay_info old_info; + struct omapfb2_mem_region *old_rg, *new_rg; int r = 0; DBG("omapfb_setup_plane\n"); @@ -52,7 +77,14 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) /* XXX uses only the first overlay */ ovl = ofbi->overlays[0]; - if (pi->enabled && !ofbi->region.size) { + old_rg = ofbi->region; + new_rg = get_mem_region(ofbi, pi->mem_idx); + if (!new_rg) { + r = -EINVAL; + goto out; + } + + if (pi->enabled && !new_rg->size) { /* * This plane's memory was freed, can't enable it * until it's reallocated. @@ -61,27 +93,60 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) goto out; } - ovl->get_overlay_info(ovl, &info); + ovl->get_overlay_info(ovl, &old_info); - info.pos_x = pi->pos_x; - info.pos_y = pi->pos_y; - info.out_width = pi->out_width; - info.out_height = pi->out_height; - info.enabled = pi->enabled; + if (old_rg != new_rg) { + ofbi->region = new_rg; + set_fb_fix(fbi); + } - r = ovl->set_overlay_info(ovl, &info); - if (r) - goto out; + if (pi->enabled) { + struct omap_overlay_info info; + + r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, + pi->out_width, pi->out_height); + if (r) + goto undo; - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); + ovl->get_overlay_info(ovl, &info); + + if (!info.enabled) { + info.enabled = pi->enabled; + r = ovl->set_overlay_info(ovl, &info); + if (r) + goto undo; + } + } else { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.enabled = pi->enabled; + info.pos_x = pi->pos_x; + info.pos_y = pi->pos_y; + info.out_width = pi->out_width; + info.out_height = pi->out_height; + + r = ovl->set_overlay_info(ovl, &info); if (r) - goto out; + goto undo; } -out: - if (r) - dev_err(fbdev->dev, "setup_plane failed\n"); + if (ovl->manager) + ovl->manager->apply(ovl->manager); + + return 0; + + undo: + if (old_rg != new_rg) { + ofbi->region = old_rg; + set_fb_fix(fbi); + } + + ovl->set_overlay_info(ovl, &old_info); + out: + dev_err(fbdev->dev, "setup_plane failed\n"); + return r; } @@ -92,8 +157,8 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) if (ofbi->num_overlays != 1) { memset(pi, 0, sizeof(*pi)); } else { - struct omap_overlay_info *ovli; struct omap_overlay *ovl; + struct omap_overlay_info *ovli; ovl = ofbi->overlays[0]; ovli = &ovl->info; @@ -103,6 +168,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) pi->enabled = ovli->enabled; pi->channel_out = 0; /* xxx */ pi->mirror = 0; + pi->mem_idx = get_mem_idx(ofbi); pi->out_width = ovli->out_width; pi->out_height = ovli->out_height; } @@ -123,11 +189,24 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) size = PAGE_ALIGN(mi->size); - rg = &ofbi->region; + rg = ofbi->region; - for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->info.enabled) - return -EBUSY; + if (atomic_read(&rg->map_count)) + return -EBUSY; + + for (i = 0; i < fbdev->num_fbs; i++) { + struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); + int j; + + if (ofbi2->region != rg) + continue; + + for (j = 0; j < ofbi2->num_overlays; j++) { + if (ofbi2->overlays[j]->info.enabled) { + r = -EBUSY; + return r; + } + } } if (rg->size != size || rg->type != mi->type) { @@ -146,7 +225,7 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_mem_region *rg; - rg = &ofbi->region; + rg = ofbi->region; memset(mi, 0, sizeof(*mi)); mi->size = rg->size; |