summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c44
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c62
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c37
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h18
4 files changed, 140 insertions, 21 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index 6635bd75affa..69bcbfca47f6 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -55,7 +55,7 @@ static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi,
if (mem_idx >= fbdev->num_fbs)
return NULL;
- return &fbdev->regions[mem_idx];
+ return omapfb_get_mem_region(&fbdev->regions[mem_idx]);
}
static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
@@ -77,11 +77,11 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
/* XXX uses only the first overlay */
ovl = ofbi->overlays[0];
- old_rg = ofbi->region;
+ old_rg = omapfb_get_mem_region(ofbi->region);
new_rg = get_mem_region(ofbi, pi->mem_idx);
if (!new_rg) {
r = -EINVAL;
- goto out;
+ goto put_old;
}
if (pi->enabled && !new_rg->size) {
@@ -90,7 +90,7 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
* until it's reallocated.
*/
r = -EINVAL;
- goto out;
+ goto put_new;
}
ovl->get_overlay_info(ovl, &old_info);
@@ -135,6 +135,9 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
if (ovl->manager)
ovl->manager->apply(ovl->manager);
+ omapfb_put_mem_region(new_rg);
+ omapfb_put_mem_region(old_rg);
+
return 0;
undo:
@@ -144,6 +147,10 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
}
ovl->set_overlay_info(ovl, &old_info);
+ put_new:
+ omapfb_put_mem_region(new_rg);
+ put_old:
+ omapfb_put_mem_region(old_rg);
out:
dev_err(fbdev->dev, "setup_plane failed\n");
@@ -181,7 +188,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg;
- int r, i;
+ int r = 0, i;
size_t size;
if (mi->type > OMAPFB_MEMTYPE_MAX)
@@ -191,8 +198,18 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
rg = ofbi->region;
- if (atomic_read(&rg->map_count))
- return -EBUSY;
+ /* FIXME probably should be a rwsem ... */
+ mutex_lock(&rg->mtx);
+ while (rg->ref) {
+ mutex_unlock(&rg->mtx);
+ schedule();
+ mutex_lock(&rg->mtx);
+ }
+
+ if (atomic_read(&rg->map_count)) {
+ r = -EBUSY;
+ goto out;
+ }
for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
@@ -204,7 +221,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
for (j = 0; j < ofbi2->num_overlays; j++) {
if (ofbi2->overlays[j]->info.enabled) {
r = -EBUSY;
- return r;
+ goto out;
}
}
}
@@ -213,11 +230,14 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
r = omapfb_realloc_fbmem(fbi, size, mi->type);
if (r) {
dev_err(fbdev->dev, "realloc fbmem failed\n");
- return r;
+ goto out;
}
}
- return 0;
+ out:
+ mutex_unlock(&rg->mtx);
+
+ return r;
}
static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
@@ -225,12 +245,14 @@ 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 = omapfb_get_mem_region(ofbi->region);
memset(mi, 0, sizeof(*mi));
mi->size = rg->size;
mi->type = rg->type;
+ omapfb_put_mem_region(rg);
+
return 0;
}
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 4a0588022b33..eb4338bbaa2b 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1019,36 +1019,48 @@ err:
* DO NOT MODIFY PAR */
static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
{
+ struct omapfb_info *ofbi = FB2OFB(fbi);
int r;
DBG("check_var(%d)\n", FB2OFB(fbi)->id);
+ omapfb_get_mem_region(ofbi->region);
+
r = check_fb_var(fbi, var);
+ omapfb_put_mem_region(ofbi->region);
+
return r;
}
/* set the video mode according to info->var */
static int omapfb_set_par(struct fb_info *fbi)
{
+ struct omapfb_info *ofbi = FB2OFB(fbi);
int r;
DBG("set_par(%d)\n", FB2OFB(fbi)->id);
+ omapfb_get_mem_region(ofbi->region);
+
set_fb_fix(fbi);
r = setup_vrfb_rotation(fbi);
if (r)
- return r;
+ goto out;
r = omapfb_apply_changes(fbi, 0);
+ out:
+ omapfb_put_mem_region(ofbi->region);
+
return r;
}
static int omapfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fbi)
{
+ struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_var_screeninfo new_var;
int r;
@@ -1064,8 +1076,12 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var,
fbi->var = new_var;
+ omapfb_get_mem_region(ofbi->region);
+
r = omapfb_apply_changes(fbi, 0);
+ omapfb_put_mem_region(ofbi->region);
+
return r;
}
@@ -1073,14 +1089,18 @@ static void mmap_user_open(struct vm_area_struct *vma)
{
struct omapfb2_mem_region *rg = vma->vm_private_data;
+ omapfb_get_mem_region(rg);
atomic_inc(&rg->map_count);
+ omapfb_put_mem_region(rg);
}
static void mmap_user_close(struct vm_area_struct *vma)
{
struct omapfb2_mem_region *rg = vma->vm_private_data;
+ omapfb_get_mem_region(rg);
atomic_dec(&rg->map_count);
+ omapfb_put_mem_region(rg);
}
static struct vm_operations_struct mmap_user_ops = {
@@ -1096,6 +1116,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
unsigned long off;
unsigned long start;
u32 len;
+ int r = -EINVAL;
if (vma->vm_end - vma->vm_start == 0)
return 0;
@@ -1103,14 +1124,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT;
- rg = ofbi->region;
+ rg = omapfb_get_mem_region(ofbi->region);
start = omapfb_get_region_paddr(ofbi);
len = fix->smem_len;
if (off >= len)
- return -EINVAL;
+ goto error;
if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
+ goto error;
off += start;
@@ -1122,11 +1143,23 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
vma->vm_ops = &mmap_user_ops;
vma->vm_private_data = rg;
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EAGAIN;
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ r = -EAGAIN;
+ goto error;
+ }
+
/* vm_ops.open won't be called for mmap itself. */
atomic_inc(&rg->map_count);
+
+ omapfb_put_mem_region(rg);
+
return 0;
+
+ error:
+ omapfb_put_mem_region(ofbi->region);
+
+ return r;
}
/* Store a single color palette entry into a pseudo palette or the hardware
@@ -1897,6 +1930,7 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
ofbi->region = &fbdev->regions[i];
ofbi->region->id = i;
+ mutex_init(&ofbi->region->mtx);
/* assign these early, so that fb alloc can use them */
ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
@@ -1927,7 +1961,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
/* setup fb_infos */
for (i = 0; i < fbdev->num_fbs; i++) {
- r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
+ struct fb_info *fbi = fbdev->fbs[i];
+ struct omapfb_info *ofbi = FB2OFB(fbi);
+
+ omapfb_get_mem_region(ofbi->region);
+ r = omapfb_fb_init(fbdev, fbi);
+ omapfb_put_mem_region(ofbi->region);
+
if (r) {
dev_err(fbdev->dev, "failed to setup fb_info\n");
return r;
@@ -1948,7 +1988,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
DBG("framebuffers registered\n");
for (i = 0; i < fbdev->num_fbs; i++) {
- r = omapfb_apply_changes(fbdev->fbs[i], 1);
+ struct fb_info *fbi = fbdev->fbs[i];
+ struct omapfb_info *ofbi = FB2OFB(fbi);
+
+ omapfb_get_mem_region(ofbi->region);
+ r = omapfb_apply_changes(fbi, 1);
+ omapfb_put_mem_region(ofbi->region);
+
if (r) {
dev_err(fbdev->dev, "failed to change mode\n");
return r;
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
index dea1aa46a7db..74c11b243100 100644
--- a/drivers/video/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev,
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
+ struct omapfb2_mem_region *rg;
enum omap_dss_rotation_type rot_type;
int r;
@@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type == ofbi->rotation_type)
goto out;
- if (ofbi->region->size) {
+ rg = omapfb_get_mem_region(ofbi->region);
+
+ if (rg->size) {
r = -EBUSY;
- goto out;
+ goto put_region;
}
ofbi->rotation_type = rot_type;
@@ -75,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev,
* Since the VRAM for this FB is not allocated at the moment we don't
* need to do any further parameter checking at this point.
*/
+put_region:
+ omapfb_put_mem_region(rg);
out:
unlock_fb_info(fbi);
@@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev,
ofbi->mirror = mirror;
+ omapfb_get_mem_region(ofbi->region);
+
memcpy(&new_var, &fbi->var, sizeof(new_var));
r = check_fb_var(fbi, &new_var);
if (r)
@@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev,
r = count;
out:
+ omapfb_put_mem_region(ofbi->region);
+
unlock_fb_info(fbi);
return r;
@@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
DBG("detaching %d\n", ofbi->overlays[i]->id);
+ omapfb_get_mem_region(ofbi->region);
+
omapfb_overlay_enable(ovl, 0);
if (ovl->manager)
ovl->manager->apply(ovl->manager);
+ omapfb_put_mem_region(ofbi->region);
+
for (t = i + 1; t < ofbi->num_overlays; t++) {
ofbi->rotation[t-1] = ofbi->rotation[t];
ofbi->overlays[t-1] = ofbi->overlays[t];
@@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
}
if (added) {
+ omapfb_get_mem_region(ofbi->region);
+
r = omapfb_apply_changes(fbi, 0);
+
+ omapfb_put_mem_region(ofbi->region);
+
if (r)
goto out;
}
@@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev,
for (i = 0; i < num_ovls; ++i)
ofbi->rotation[i] = rotation[i];
+ omapfb_get_mem_region(ofbi->region);
+
r = omapfb_apply_changes(fbi, 0);
+
+ omapfb_put_mem_region(ofbi->region);
+
if (r)
goto out;
@@ -429,6 +452,14 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
rg = ofbi->region;
+ /* FIXME probably should be a rwsem ... */
+ mutex_lock(&rg->mtx);
+ while (rg->ref) {
+ mutex_unlock(&rg->mtx);
+ schedule();
+ mutex_lock(&rg->mtx);
+ }
+
if (atomic_read(&rg->map_count)) {
r = -EBUSY;
goto out;
@@ -459,6 +490,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
r = count;
out:
+ mutex_unlock(&rg->mtx);
+
unlock_fb_info(fbi);
return r;
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index 02f1ba9b228c..db3aef5172c5 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -52,6 +52,8 @@ struct omapfb2_mem_region {
u8 type; /* OMAPFB_PLANE_MEM_* */
bool alloc; /* allocated by the driver */
bool map; /* kernel mapped by the driver */
+ struct mutex mtx;
+ unsigned int ref;
atomic_t map_count;
};
@@ -159,4 +161,20 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
return ovl->set_overlay_info(ovl, &info);
}
+static inline struct omapfb2_mem_region *
+omapfb_get_mem_region(struct omapfb2_mem_region *rg)
+{
+ mutex_lock(&rg->mtx);
+ rg->ref++;
+ mutex_unlock(&rg->mtx);
+ return rg;
+}
+
+static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg)
+{
+ mutex_lock(&rg->mtx);
+ rg->ref--;
+ mutex_unlock(&rg->mtx);
+}
+
#endif
OpenPOWER on IntegriCloud