2009-08-04 13:12:50 +00:00
|
|
|
/*
|
|
|
|
* linux/drivers/video/omap2/omapfb-ioctl.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008 Nokia Corporation
|
|
|
|
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
|
|
|
*
|
|
|
|
* Some code and ideas taken from drivers/video/omap/ driver
|
|
|
|
* by Imre Deak.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
|
|
* the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/fb.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/omapfb.h>
|
|
|
|
#include <linux/vmalloc.h>
|
2011-07-10 17:20:26 +00:00
|
|
|
#include <linux/export.h>
|
2012-11-23 08:50:32 +00:00
|
|
|
#include <linux/sizes.h>
|
2009-08-04 13:12:50 +00:00
|
|
|
|
2016-05-31 08:43:12 +00:00
|
|
|
#include <video/omapfb_dss.h>
|
2012-10-08 11:52:24 +00:00
|
|
|
#include <video/omapvrfb.h>
|
2009-08-04 13:12:50 +00:00
|
|
|
|
|
|
|
#include "omapfb.h"
|
|
|
|
|
2010-03-17 18:36:51 +00:00
|
|
|
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;
|
|
|
|
|
2010-03-17 19:42:06 +00:00
|
|
|
return &fbdev->regions[mem_idx];
|
2010-03-17 18:36:51 +00:00
|
|
|
}
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
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;
|
2010-03-17 18:36:51 +00:00
|
|
|
struct omap_overlay_info old_info;
|
|
|
|
struct omapfb2_mem_region *old_rg, *new_rg;
|
2009-08-04 13:12:50 +00:00
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
DBG("omapfb_setup_plane\n");
|
|
|
|
|
2012-05-10 11:19:56 +00:00
|
|
|
if (ofbi->num_overlays == 0) {
|
2009-08-04 13:12:50 +00:00
|
|
|
r = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX uses only the first overlay */
|
|
|
|
ovl = ofbi->overlays[0];
|
|
|
|
|
2010-03-17 19:42:06 +00:00
|
|
|
old_rg = ofbi->region;
|
2010-03-17 18:36:51 +00:00
|
|
|
new_rg = get_mem_region(ofbi, pi->mem_idx);
|
|
|
|
if (!new_rg) {
|
|
|
|
r = -EINVAL;
|
2010-03-17 19:42:06 +00:00
|
|
|
goto out;
|
2010-03-17 18:36:51 +00:00
|
|
|
}
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
/* Take the locks in a specific order to keep lockdep happy */
|
|
|
|
if (old_rg->id < new_rg->id) {
|
|
|
|
omapfb_get_mem_region(old_rg);
|
|
|
|
omapfb_get_mem_region(new_rg);
|
|
|
|
} else if (new_rg->id < old_rg->id) {
|
|
|
|
omapfb_get_mem_region(new_rg);
|
|
|
|
omapfb_get_mem_region(old_rg);
|
|
|
|
} else
|
|
|
|
omapfb_get_mem_region(old_rg);
|
|
|
|
|
2010-03-17 18:36:51 +00:00
|
|
|
if (pi->enabled && !new_rg->size) {
|
2009-08-04 13:12:50 +00:00
|
|
|
/*
|
|
|
|
* This plane's memory was freed, can't enable it
|
|
|
|
* until it's reallocated.
|
|
|
|
*/
|
|
|
|
r = -EINVAL;
|
2010-03-17 19:42:06 +00:00
|
|
|
goto put_mem;
|
2009-08-04 13:12:50 +00:00
|
|
|
}
|
|
|
|
|
2010-03-17 18:36:51 +00:00
|
|
|
ovl->get_overlay_info(ovl, &old_info);
|
|
|
|
|
|
|
|
if (old_rg != new_rg) {
|
|
|
|
ofbi->region = new_rg;
|
|
|
|
set_fb_fix(fbi);
|
|
|
|
}
|
2009-08-04 13:12:50 +00:00
|
|
|
|
OMAPDSS: APPLY: rewrite overlay enable/disable
Overlays are currently enabled and disabled with a boolean in the struct
omap_overlay_info. The overlay info is set with ovl->set_overlay_info(),
and made into use with mgr->apply().
This doesn't work properly, as the enable/disable status may affect also
other overlays, for example when using fifo-merge. Thus the enabling and
disabling of the overlay needs to be done outside the normal overlay
configuration.
This patch achieves that by doing the following things:
1) Add function pointers to struct omap_overlay: enable(), disable() and
is_enabled(). These are used to do the obvious. The functions may block.
2) Move the "enabled" field from struct omap_overlay to ovl_priv_data.
3) Add a new route for settings to be applied to the HW, called
"extra_info". The status of the normal info and extra_info are tracked
separately.
The point here is to allow the normal info to be changed and
applied in non-blocking matter, whereas the extra_info can only be
changed when holding the mutex. This makes it possible to, for example,
set the overlay enable flag, apply it, and wait until the HW has taken
the flag into use.
This is not possible if the enable flag would be in the normal info, as
a new value for the flag could be set at any time from the users of
omapdss.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2011-11-15 14:37:53 +00:00
|
|
|
if (!pi->enabled) {
|
|
|
|
r = ovl->disable(ovl);
|
|
|
|
if (r)
|
|
|
|
goto undo;
|
|
|
|
}
|
2009-08-04 13:12:50 +00:00
|
|
|
|
OMAPDSS: APPLY: rewrite overlay enable/disable
Overlays are currently enabled and disabled with a boolean in the struct
omap_overlay_info. The overlay info is set with ovl->set_overlay_info(),
and made into use with mgr->apply().
This doesn't work properly, as the enable/disable status may affect also
other overlays, for example when using fifo-merge. Thus the enabling and
disabling of the overlay needs to be done outside the normal overlay
configuration.
This patch achieves that by doing the following things:
1) Add function pointers to struct omap_overlay: enable(), disable() and
is_enabled(). These are used to do the obvious. The functions may block.
2) Move the "enabled" field from struct omap_overlay to ovl_priv_data.
3) Add a new route for settings to be applied to the HW, called
"extra_info". The status of the normal info and extra_info are tracked
separately.
The point here is to allow the normal info to be changed and
applied in non-blocking matter, whereas the extra_info can only be
changed when holding the mutex. This makes it possible to, for example,
set the overlay enable flag, apply it, and wait until the HW has taken
the flag into use.
This is not possible if the enable flag would be in the normal info, as
a new value for the flag could be set at any time from the users of
omapdss.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2011-11-15 14:37:53 +00:00
|
|
|
if (pi->enabled) {
|
2010-03-17 18:36:51 +00:00
|
|
|
r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
|
|
|
|
pi->out_width, pi->out_height);
|
|
|
|
if (r)
|
|
|
|
goto undo;
|
|
|
|
} else {
|
|
|
|
struct omap_overlay_info info;
|
2009-08-04 13:12:50 +00:00
|
|
|
|
2010-03-17 18:36:51 +00:00
|
|
|
ovl->get_overlay_info(ovl, &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;
|
|
|
|
|
|
|
|
r = ovl->set_overlay_info(ovl, &info);
|
2009-08-04 13:12:50 +00:00
|
|
|
if (r)
|
2010-03-17 18:36:51 +00:00
|
|
|
goto undo;
|
2009-08-04 13:12:50 +00:00
|
|
|
}
|
|
|
|
|
2015-01-30 07:59:46 +00:00
|
|
|
if (ovl->manager) {
|
|
|
|
r = ovl->manager->apply(ovl->manager);
|
|
|
|
if (r)
|
|
|
|
goto undo;
|
|
|
|
}
|
2010-03-17 18:36:51 +00:00
|
|
|
|
OMAPDSS: APPLY: rewrite overlay enable/disable
Overlays are currently enabled and disabled with a boolean in the struct
omap_overlay_info. The overlay info is set with ovl->set_overlay_info(),
and made into use with mgr->apply().
This doesn't work properly, as the enable/disable status may affect also
other overlays, for example when using fifo-merge. Thus the enabling and
disabling of the overlay needs to be done outside the normal overlay
configuration.
This patch achieves that by doing the following things:
1) Add function pointers to struct omap_overlay: enable(), disable() and
is_enabled(). These are used to do the obvious. The functions may block.
2) Move the "enabled" field from struct omap_overlay to ovl_priv_data.
3) Add a new route for settings to be applied to the HW, called
"extra_info". The status of the normal info and extra_info are tracked
separately.
The point here is to allow the normal info to be changed and
applied in non-blocking matter, whereas the extra_info can only be
changed when holding the mutex. This makes it possible to, for example,
set the overlay enable flag, apply it, and wait until the HW has taken
the flag into use.
This is not possible if the enable flag would be in the normal info, as
a new value for the flag could be set at any time from the users of
omapdss.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2011-11-15 14:37:53 +00:00
|
|
|
if (pi->enabled) {
|
|
|
|
r = ovl->enable(ovl);
|
|
|
|
if (r)
|
|
|
|
goto undo;
|
|
|
|
}
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
/* Release the locks in a specific order to keep lockdep happy */
|
|
|
|
if (old_rg->id > new_rg->id) {
|
|
|
|
omapfb_put_mem_region(old_rg);
|
|
|
|
omapfb_put_mem_region(new_rg);
|
|
|
|
} else if (new_rg->id > old_rg->id) {
|
|
|
|
omapfb_put_mem_region(new_rg);
|
|
|
|
omapfb_put_mem_region(old_rg);
|
|
|
|
} else
|
|
|
|
omapfb_put_mem_region(old_rg);
|
|
|
|
|
2010-03-17 18:36:51 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
undo:
|
|
|
|
if (old_rg != new_rg) {
|
|
|
|
ofbi->region = old_rg;
|
|
|
|
set_fb_fix(fbi);
|
|
|
|
}
|
|
|
|
|
|
|
|
ovl->set_overlay_info(ovl, &old_info);
|
2010-03-17 19:42:06 +00:00
|
|
|
put_mem:
|
2012-12-13 11:19:05 +00:00
|
|
|
/* Release the locks in a specific order to keep lockdep happy */
|
|
|
|
if (old_rg->id > new_rg->id) {
|
|
|
|
omapfb_put_mem_region(old_rg);
|
|
|
|
omapfb_put_mem_region(new_rg);
|
|
|
|
} else if (new_rg->id > old_rg->id) {
|
|
|
|
omapfb_put_mem_region(new_rg);
|
|
|
|
omapfb_put_mem_region(old_rg);
|
|
|
|
} else
|
|
|
|
omapfb_put_mem_region(old_rg);
|
2010-03-17 18:36:51 +00:00
|
|
|
out:
|
|
|
|
dev_err(fbdev->dev, "setup_plane failed\n");
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
|
|
|
|
{
|
|
|
|
struct omapfb_info *ofbi = FB2OFB(fbi);
|
|
|
|
|
2012-05-10 11:19:56 +00:00
|
|
|
if (ofbi->num_overlays == 0) {
|
2009-08-04 13:12:50 +00:00
|
|
|
memset(pi, 0, sizeof(*pi));
|
|
|
|
} else {
|
|
|
|
struct omap_overlay *ovl;
|
2011-11-16 12:11:56 +00:00
|
|
|
struct omap_overlay_info ovli;
|
2009-08-04 13:12:50 +00:00
|
|
|
|
|
|
|
ovl = ofbi->overlays[0];
|
2011-11-16 12:11:56 +00:00
|
|
|
ovl->get_overlay_info(ovl, &ovli);
|
2009-08-04 13:12:50 +00:00
|
|
|
|
2011-11-16 12:11:56 +00:00
|
|
|
pi->pos_x = ovli.pos_x;
|
|
|
|
pi->pos_y = ovli.pos_y;
|
OMAPDSS: APPLY: rewrite overlay enable/disable
Overlays are currently enabled and disabled with a boolean in the struct
omap_overlay_info. The overlay info is set with ovl->set_overlay_info(),
and made into use with mgr->apply().
This doesn't work properly, as the enable/disable status may affect also
other overlays, for example when using fifo-merge. Thus the enabling and
disabling of the overlay needs to be done outside the normal overlay
configuration.
This patch achieves that by doing the following things:
1) Add function pointers to struct omap_overlay: enable(), disable() and
is_enabled(). These are used to do the obvious. The functions may block.
2) Move the "enabled" field from struct omap_overlay to ovl_priv_data.
3) Add a new route for settings to be applied to the HW, called
"extra_info". The status of the normal info and extra_info are tracked
separately.
The point here is to allow the normal info to be changed and
applied in non-blocking matter, whereas the extra_info can only be
changed when holding the mutex. This makes it possible to, for example,
set the overlay enable flag, apply it, and wait until the HW has taken
the flag into use.
This is not possible if the enable flag would be in the normal info, as
a new value for the flag could be set at any time from the users of
omapdss.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2011-11-15 14:37:53 +00:00
|
|
|
pi->enabled = ovl->is_enabled(ovl);
|
2009-08-04 13:12:50 +00:00
|
|
|
pi->channel_out = 0; /* xxx */
|
|
|
|
pi->mirror = 0;
|
2010-03-17 18:36:51 +00:00
|
|
|
pi->mem_idx = get_mem_idx(ofbi);
|
2011-11-16 12:11:56 +00:00
|
|
|
pi->out_width = ovli.out_width;
|
|
|
|
pi->out_height = ovli.out_height;
|
2009-08-04 13:12:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2012-12-07 14:47:28 +00:00
|
|
|
struct omap_dss_device *display = fb2display(fbi);
|
2009-08-04 13:12:50 +00:00
|
|
|
struct omapfb2_mem_region *rg;
|
2010-03-17 18:43:23 +00:00
|
|
|
int r = 0, i;
|
2009-08-04 13:12:50 +00:00
|
|
|
size_t size;
|
|
|
|
|
2011-04-18 10:18:20 +00:00
|
|
|
if (mi->type != OMAPFB_MEMTYPE_SDRAM)
|
2009-08-04 13:12:50 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
size = PAGE_ALIGN(mi->size);
|
|
|
|
|
2012-12-07 14:47:28 +00:00
|
|
|
if (display && display->driver->sync)
|
|
|
|
display->driver->sync(display);
|
|
|
|
|
2012-12-04 12:55:18 +00:00
|
|
|
rg = ofbi->region;
|
2010-03-17 18:43:23 +00:00
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
down_write_nested(&rg->lock, rg->id);
|
|
|
|
atomic_inc(&rg->lock_count);
|
|
|
|
|
2012-03-09 00:42:49 +00:00
|
|
|
if (rg->size == size && rg->type == mi->type)
|
|
|
|
goto out;
|
|
|
|
|
2010-03-17 18:43:23 +00:00
|
|
|
if (atomic_read(&rg->map_count)) {
|
|
|
|
r = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
2010-03-17 18:36:51 +00:00
|
|
|
|
|
|
|
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++) {
|
OMAPDSS: APPLY: rewrite overlay enable/disable
Overlays are currently enabled and disabled with a boolean in the struct
omap_overlay_info. The overlay info is set with ovl->set_overlay_info(),
and made into use with mgr->apply().
This doesn't work properly, as the enable/disable status may affect also
other overlays, for example when using fifo-merge. Thus the enabling and
disabling of the overlay needs to be done outside the normal overlay
configuration.
This patch achieves that by doing the following things:
1) Add function pointers to struct omap_overlay: enable(), disable() and
is_enabled(). These are used to do the obvious. The functions may block.
2) Move the "enabled" field from struct omap_overlay to ovl_priv_data.
3) Add a new route for settings to be applied to the HW, called
"extra_info". The status of the normal info and extra_info are tracked
separately.
The point here is to allow the normal info to be changed and
applied in non-blocking matter, whereas the extra_info can only be
changed when holding the mutex. This makes it possible to, for example,
set the overlay enable flag, apply it, and wait until the HW has taken
the flag into use.
This is not possible if the enable flag would be in the normal info, as
a new value for the flag could be set at any time from the users of
omapdss.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2011-11-15 14:37:53 +00:00
|
|
|
struct omap_overlay *ovl;
|
|
|
|
ovl = ofbi2->overlays[j];
|
|
|
|
if (ovl->is_enabled(ovl)) {
|
2010-03-17 18:36:51 +00:00
|
|
|
r = -EBUSY;
|
2010-03-17 18:43:23 +00:00
|
|
|
goto out;
|
2010-03-17 18:36:51 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-04 13:12:50 +00:00
|
|
|
}
|
|
|
|
|
2012-03-09 00:42:49 +00:00
|
|
|
r = omapfb_realloc_fbmem(fbi, size, mi->type);
|
|
|
|
if (r) {
|
|
|
|
dev_err(fbdev->dev, "realloc fbmem failed\n");
|
|
|
|
goto out;
|
2009-08-04 13:12:50 +00:00
|
|
|
}
|
|
|
|
|
2010-03-17 18:43:23 +00:00
|
|
|
out:
|
2012-12-13 11:19:05 +00:00
|
|
|
atomic_dec(&rg->lock_count);
|
|
|
|
up_write(&rg->lock);
|
|
|
|
|
2010-03-17 18:43:23 +00:00
|
|
|
return r;
|
2009-08-04 13:12:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
rg = omapfb_get_mem_region(ofbi->region);
|
2009-08-04 13:12:50 +00:00
|
|
|
memset(mi, 0, sizeof(*mi));
|
|
|
|
|
|
|
|
mi->size = rg->size;
|
|
|
|
mi->type = rg->type;
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_put_mem_region(rg);
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-12-04 12:20:11 +00:00
|
|
|
static int omapfb_update_window(struct fb_info *fbi,
|
2009-08-04 13:12:50 +00:00
|
|
|
u32 x, u32 y, u32 w, u32 h)
|
|
|
|
{
|
|
|
|
struct omap_dss_device *display = fb2display(fbi);
|
|
|
|
u16 dw, dh;
|
|
|
|
|
|
|
|
if (!display)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (w == 0 || h == 0)
|
|
|
|
return 0;
|
|
|
|
|
2010-01-11 11:54:33 +00:00
|
|
|
display->driver->get_resolution(display, &dw, &dh);
|
2009-08-04 13:12:50 +00:00
|
|
|
|
|
|
|
if (x + w > dw || y + h > dh)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2010-01-12 12:16:41 +00:00
|
|
|
return display->driver->update(display, x, y, w, h);
|
2009-08-04 13:12:50 +00:00
|
|
|
}
|
|
|
|
|
2011-04-30 13:55:12 +00:00
|
|
|
int omapfb_set_update_mode(struct fb_info *fbi,
|
2009-08-04 13:12:50 +00:00
|
|
|
enum omapfb_update_mode mode)
|
|
|
|
{
|
|
|
|
struct omap_dss_device *display = fb2display(fbi);
|
2011-04-30 13:55:12 +00:00
|
|
|
struct omapfb_info *ofbi = FB2OFB(fbi);
|
|
|
|
struct omapfb2_device *fbdev = ofbi->fbdev;
|
|
|
|
struct omapfb_display_data *d;
|
2009-08-04 13:12:50 +00:00
|
|
|
int r;
|
|
|
|
|
2011-04-30 13:55:12 +00:00
|
|
|
if (!display)
|
2009-08-04 13:12:50 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2011-04-30 13:55:12 +00:00
|
|
|
if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
|
|
|
|
return -EINVAL;
|
2009-08-04 13:12:50 +00:00
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_lock(fbdev);
|
|
|
|
|
2011-04-30 13:55:12 +00:00
|
|
|
d = get_display_data(fbdev, display);
|
2009-08-04 13:12:50 +00:00
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
if (d->update_mode == mode) {
|
|
|
|
omapfb_unlock(fbdev);
|
2011-04-30 13:55:12 +00:00
|
|
|
return 0;
|
2012-12-13 11:19:05 +00:00
|
|
|
}
|
2011-04-30 13:55:12 +00:00
|
|
|
|
|
|
|
r = 0;
|
|
|
|
|
|
|
|
if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
|
|
|
|
if (mode == OMAPFB_AUTO_UPDATE)
|
|
|
|
omapfb_start_auto_update(fbdev, display);
|
|
|
|
else /* MANUAL_UPDATE */
|
|
|
|
omapfb_stop_auto_update(fbdev, display);
|
|
|
|
|
|
|
|
d->update_mode = mode;
|
|
|
|
} else { /* AUTO_UPDATE */
|
|
|
|
if (mode == OMAPFB_MANUAL_UPDATE)
|
|
|
|
r = -EINVAL;
|
2009-08-04 13:12:50 +00:00
|
|
|
}
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_unlock(fbdev);
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-04-30 13:55:12 +00:00
|
|
|
int omapfb_get_update_mode(struct fb_info *fbi,
|
2009-08-04 13:12:50 +00:00
|
|
|
enum omapfb_update_mode *mode)
|
|
|
|
{
|
|
|
|
struct omap_dss_device *display = fb2display(fbi);
|
2011-04-30 13:55:12 +00:00
|
|
|
struct omapfb_info *ofbi = FB2OFB(fbi);
|
|
|
|
struct omapfb2_device *fbdev = ofbi->fbdev;
|
|
|
|
struct omapfb_display_data *d;
|
2009-08-04 13:12:50 +00:00
|
|
|
|
2010-01-11 14:12:31 +00:00
|
|
|
if (!display)
|
2009-08-04 13:12:50 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_lock(fbdev);
|
|
|
|
|
2011-04-30 13:55:12 +00:00
|
|
|
d = get_display_data(fbdev, display);
|
2009-08-04 13:12:50 +00:00
|
|
|
|
2011-04-30 13:55:12 +00:00
|
|
|
*mode = d->update_mode;
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_unlock(fbdev);
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX this color key handling is a hack... */
|
|
|
|
static struct omapfb_color_key omapfb_color_keys[2];
|
|
|
|
|
|
|
|
static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
|
|
|
|
struct omapfb_color_key *ck)
|
|
|
|
{
|
|
|
|
struct omap_overlay_manager_info info;
|
|
|
|
enum omap_dss_trans_key_type kt;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
mgr->get_manager_info(mgr, &info);
|
|
|
|
|
|
|
|
if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
|
|
|
|
info.trans_enabled = false;
|
|
|
|
omapfb_color_keys[mgr->id] = *ck;
|
|
|
|
|
|
|
|
r = mgr->set_manager_info(mgr, &info);
|
|
|
|
if (r)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = mgr->apply(mgr);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ck->key_type) {
|
|
|
|
case OMAPFB_COLOR_KEY_GFX_DST:
|
|
|
|
kt = OMAP_DSS_COLOR_KEY_GFX_DST;
|
|
|
|
break;
|
|
|
|
case OMAPFB_COLOR_KEY_VID_SRC:
|
|
|
|
kt = OMAP_DSS_COLOR_KEY_VID_SRC;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
info.default_color = ck->background;
|
|
|
|
info.trans_key = ck->trans_key;
|
|
|
|
info.trans_key_type = kt;
|
|
|
|
info.trans_enabled = true;
|
|
|
|
|
|
|
|
omapfb_color_keys[mgr->id] = *ck;
|
|
|
|
|
|
|
|
r = mgr->set_manager_info(mgr, &info);
|
|
|
|
if (r)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = mgr->apply(mgr);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int omapfb_set_color_key(struct fb_info *fbi,
|
|
|
|
struct omapfb_color_key *ck)
|
|
|
|
{
|
|
|
|
struct omapfb_info *ofbi = FB2OFB(fbi);
|
2012-12-13 11:19:05 +00:00
|
|
|
struct omapfb2_device *fbdev = ofbi->fbdev;
|
2009-08-04 13:12:50 +00:00
|
|
|
int r;
|
|
|
|
int i;
|
|
|
|
struct omap_overlay_manager *mgr = NULL;
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_lock(fbdev);
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
for (i = 0; i < ofbi->num_overlays; i++) {
|
|
|
|
if (ofbi->overlays[i]->manager) {
|
|
|
|
mgr = ofbi->overlays[i]->manager;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mgr) {
|
|
|
|
r = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = _omapfb_set_color_key(mgr, ck);
|
|
|
|
err:
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_unlock(fbdev);
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int omapfb_get_color_key(struct fb_info *fbi,
|
|
|
|
struct omapfb_color_key *ck)
|
|
|
|
{
|
|
|
|
struct omapfb_info *ofbi = FB2OFB(fbi);
|
2012-12-13 11:19:05 +00:00
|
|
|
struct omapfb2_device *fbdev = ofbi->fbdev;
|
2009-08-04 13:12:50 +00:00
|
|
|
struct omap_overlay_manager *mgr = NULL;
|
|
|
|
int r = 0;
|
|
|
|
int i;
|
|
|
|
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_lock(fbdev);
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
for (i = 0; i < ofbi->num_overlays; i++) {
|
|
|
|
if (ofbi->overlays[i]->manager) {
|
|
|
|
mgr = ofbi->overlays[i]->manager;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mgr) {
|
|
|
|
r = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ck = omapfb_color_keys[mgr->id];
|
|
|
|
err:
|
2012-12-13 11:19:05 +00:00
|
|
|
omapfb_unlock(fbdev);
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int omapfb_memory_read(struct fb_info *fbi,
|
|
|
|
struct omapfb_memory_read *mr)
|
|
|
|
{
|
|
|
|
struct omap_dss_device *display = fb2display(fbi);
|
|
|
|
void *buf;
|
|
|
|
int r;
|
|
|
|
|
2010-01-08 14:56:44 +00:00
|
|
|
if (!display || !display->driver->memory_read)
|
2009-08-04 13:12:50 +00:00
|
|
|
return -ENOENT;
|
|
|
|
|
Remove 'type' argument from access_ok() function
Nobody has actually used the type (VERIFY_READ vs VERIFY_WRITE) argument
of the user address range verification function since we got rid of the
old racy i386-only code to walk page tables by hand.
It existed because the original 80386 would not honor the write protect
bit when in kernel mode, so you had to do COW by hand before doing any
user access. But we haven't supported that in a long time, and these
days the 'type' argument is a purely historical artifact.
A discussion about extending 'user_access_begin()' to do the range
checking resulted this patch, because there is no way we're going to
move the old VERIFY_xyz interface to that model. And it's best done at
the end of the merge window when I've done most of my merges, so let's
just get this done once and for all.
This patch was mostly done with a sed-script, with manual fix-ups for
the cases that weren't of the trivial 'access_ok(VERIFY_xyz' form.
There were a couple of notable cases:
- csky still had the old "verify_area()" name as an alias.
- the iter_iov code had magical hardcoded knowledge of the actual
values of VERIFY_{READ,WRITE} (not that they mattered, since nothing
really used it)
- microblaze used the type argument for a debug printout
but other than those oddities this should be a total no-op patch.
I tried to fix up all architectures, did fairly extensive grepping for
access_ok() uses, and the changes are trivial, but I may have missed
something. Any missed conversion should be trivially fixable, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-01-04 02:57:57 +00:00
|
|
|
if (!access_ok(mr->buffer, mr->buffer_size))
|
2009-08-04 13:12:50 +00:00
|
|
|
return -EFAULT;
|
|
|
|
|
2018-09-26 16:11:22 +00:00
|
|
|
if (mr->w > 4096 || mr->h > 4096)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
if (mr->w * mr->h * 3 > mr->buffer_size)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
buf = vmalloc(mr->buffer_size);
|
|
|
|
if (!buf) {
|
|
|
|
DBG("vmalloc failed\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2010-01-08 14:56:44 +00:00
|
|
|
r = display->driver->memory_read(display, buf, mr->buffer_size,
|
2009-08-04 13:12:50 +00:00
|
|
|
mr->x, mr->y, mr->w, mr->h);
|
|
|
|
|
|
|
|
if (r > 0) {
|
2018-09-26 16:11:22 +00:00
|
|
|
if (copy_to_user(mr->buffer, buf, r))
|
2009-08-04 13:12:50 +00:00
|
|
|
r = -EFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
vfree(buf);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
|
|
|
|
struct omapfb_ovl_colormode *mode)
|
|
|
|
{
|
|
|
|
int ovl_idx = mode->overlay_idx;
|
|
|
|
int mode_idx = mode->mode_idx;
|
|
|
|
struct omap_overlay *ovl;
|
|
|
|
enum omap_color_mode supported_modes;
|
|
|
|
struct fb_var_screeninfo var;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (ovl_idx >= fbdev->num_overlays)
|
|
|
|
return -ENODEV;
|
|
|
|
ovl = fbdev->overlays[ovl_idx];
|
|
|
|
supported_modes = ovl->supported_modes;
|
|
|
|
|
|
|
|
mode_idx = mode->mode_idx;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(supported_modes) * 8; i++) {
|
|
|
|
if (!(supported_modes & (1 << i)))
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* It's possible that the FB doesn't support a mode
|
|
|
|
* that is supported by the overlay, so call the
|
|
|
|
* following here.
|
|
|
|
*/
|
|
|
|
if (dss_mode_to_fb_mode(1 << i, &var) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
mode_idx--;
|
|
|
|
if (mode_idx < 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == sizeof(supported_modes) * 8)
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
mode->bits_per_pixel = var.bits_per_pixel;
|
|
|
|
mode->nonstd = var.nonstd;
|
|
|
|
mode->red = var.red;
|
|
|
|
mode->green = var.green;
|
|
|
|
mode->blue = var.blue;
|
|
|
|
mode->transp = var.transp;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int omapfb_wait_for_go(struct fb_info *fbi)
|
|
|
|
{
|
|
|
|
struct omapfb_info *ofbi = FB2OFB(fbi);
|
|
|
|
int r = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ofbi->num_overlays; ++i) {
|
|
|
|
struct omap_overlay *ovl = ofbi->overlays[i];
|
|
|
|
r = ovl->wait_for_go(ovl);
|
|
|
|
if (r)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct omapfb_info *ofbi = FB2OFB(fbi);
|
|
|
|
struct omapfb2_device *fbdev = ofbi->fbdev;
|
|
|
|
struct omap_dss_device *display = fb2display(fbi);
|
2012-09-10 09:13:39 +00:00
|
|
|
struct omap_overlay_manager *mgr;
|
2009-08-04 13:12:50 +00:00
|
|
|
|
|
|
|
union {
|
|
|
|
struct omapfb_update_window_old uwnd_o;
|
|
|
|
struct omapfb_update_window uwnd;
|
|
|
|
struct omapfb_plane_info plane_info;
|
|
|
|
struct omapfb_caps caps;
|
|
|
|
struct omapfb_mem_info mem_info;
|
|
|
|
struct omapfb_color_key color_key;
|
|
|
|
struct omapfb_ovl_colormode ovl_colormode;
|
|
|
|
enum omapfb_update_mode update_mode;
|
|
|
|
int test_num;
|
|
|
|
struct omapfb_memory_read memory_read;
|
|
|
|
struct omapfb_vram_info vram_info;
|
|
|
|
struct omapfb_tearsync_info tearsync_info;
|
2010-01-14 15:32:13 +00:00
|
|
|
struct omapfb_display_info display_info;
|
2010-07-02 20:54:56 +00:00
|
|
|
u32 crt;
|
2009-08-04 13:12:50 +00:00
|
|
|
} p;
|
|
|
|
|
|
|
|
int r = 0;
|
|
|
|
|
2019-01-11 13:34:38 +00:00
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
switch (cmd) {
|
|
|
|
case OMAPFB_SYNC_GFX:
|
|
|
|
DBG("ioctl SYNC_GFX\n");
|
2010-01-12 12:16:41 +00:00
|
|
|
if (!display || !display->driver->sync) {
|
2009-08-04 13:12:50 +00:00
|
|
|
/* DSS1 never returns an error here, so we neither */
|
|
|
|
/*r = -EINVAL;*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-01-12 12:16:41 +00:00
|
|
|
r = display->driver->sync(display);
|
2009-08-04 13:12:50 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_UPDATE_WINDOW_OLD:
|
|
|
|
DBG("ioctl UPDATE_WINDOW_OLD\n");
|
2010-01-12 12:16:41 +00:00
|
|
|
if (!display || !display->driver->update) {
|
2009-08-04 13:12:50 +00:00
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (copy_from_user(&p.uwnd_o,
|
|
|
|
(void __user *)arg,
|
|
|
|
sizeof(p.uwnd_o))) {
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-12-04 12:20:11 +00:00
|
|
|
r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
|
2009-08-04 13:12:50 +00:00
|
|
|
p.uwnd_o.width, p.uwnd_o.height);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_UPDATE_WINDOW:
|
|
|
|
DBG("ioctl UPDATE_WINDOW\n");
|
2010-01-12 12:16:41 +00:00
|
|
|
if (!display || !display->driver->update) {
|
2009-08-04 13:12:50 +00:00
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (copy_from_user(&p.uwnd, (void __user *)arg,
|
|
|
|
sizeof(p.uwnd))) {
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-12-04 12:20:11 +00:00
|
|
|
r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
|
2009-08-04 13:12:50 +00:00
|
|
|
p.uwnd.width, p.uwnd.height);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_SETUP_PLANE:
|
|
|
|
DBG("ioctl SETUP_PLANE\n");
|
|
|
|
if (copy_from_user(&p.plane_info, (void __user *)arg,
|
|
|
|
sizeof(p.plane_info)))
|
|
|
|
r = -EFAULT;
|
|
|
|
else
|
|
|
|
r = omapfb_setup_plane(fbi, &p.plane_info);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_QUERY_PLANE:
|
|
|
|
DBG("ioctl QUERY_PLANE\n");
|
|
|
|
r = omapfb_query_plane(fbi, &p.plane_info);
|
|
|
|
if (r < 0)
|
|
|
|
break;
|
|
|
|
if (copy_to_user((void __user *)arg, &p.plane_info,
|
|
|
|
sizeof(p.plane_info)))
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_SETUP_MEM:
|
|
|
|
DBG("ioctl SETUP_MEM\n");
|
|
|
|
if (copy_from_user(&p.mem_info, (void __user *)arg,
|
|
|
|
sizeof(p.mem_info)))
|
|
|
|
r = -EFAULT;
|
|
|
|
else
|
|
|
|
r = omapfb_setup_mem(fbi, &p.mem_info);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_QUERY_MEM:
|
|
|
|
DBG("ioctl QUERY_MEM\n");
|
|
|
|
r = omapfb_query_mem(fbi, &p.mem_info);
|
|
|
|
if (r < 0)
|
|
|
|
break;
|
|
|
|
if (copy_to_user((void __user *)arg, &p.mem_info,
|
|
|
|
sizeof(p.mem_info)))
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_GET_CAPS:
|
|
|
|
DBG("ioctl GET_CAPS\n");
|
|
|
|
if (!display) {
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&p.caps, 0, sizeof(p.caps));
|
|
|
|
if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
|
|
|
|
p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
|
|
|
|
if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
|
|
|
|
p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
|
|
|
|
|
|
|
|
if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_GET_OVERLAY_COLORMODE:
|
|
|
|
DBG("ioctl GET_OVERLAY_COLORMODE\n");
|
|
|
|
if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
|
|
|
|
sizeof(p.ovl_colormode))) {
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
|
|
|
|
if (r < 0)
|
|
|
|
break;
|
|
|
|
if (copy_to_user((void __user *)arg, &p.ovl_colormode,
|
|
|
|
sizeof(p.ovl_colormode)))
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_SET_UPDATE_MODE:
|
|
|
|
DBG("ioctl SET_UPDATE_MODE\n");
|
|
|
|
if (get_user(p.update_mode, (int __user *)arg))
|
|
|
|
r = -EFAULT;
|
|
|
|
else
|
|
|
|
r = omapfb_set_update_mode(fbi, p.update_mode);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_GET_UPDATE_MODE:
|
|
|
|
DBG("ioctl GET_UPDATE_MODE\n");
|
|
|
|
r = omapfb_get_update_mode(fbi, &p.update_mode);
|
|
|
|
if (r)
|
|
|
|
break;
|
|
|
|
if (put_user(p.update_mode,
|
|
|
|
(enum omapfb_update_mode __user *)arg))
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_SET_COLOR_KEY:
|
|
|
|
DBG("ioctl SET_COLOR_KEY\n");
|
|
|
|
if (copy_from_user(&p.color_key, (void __user *)arg,
|
|
|
|
sizeof(p.color_key)))
|
|
|
|
r = -EFAULT;
|
|
|
|
else
|
|
|
|
r = omapfb_set_color_key(fbi, &p.color_key);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_GET_COLOR_KEY:
|
|
|
|
DBG("ioctl GET_COLOR_KEY\n");
|
|
|
|
r = omapfb_get_color_key(fbi, &p.color_key);
|
|
|
|
if (r)
|
|
|
|
break;
|
|
|
|
if (copy_to_user((void __user *)arg, &p.color_key,
|
|
|
|
sizeof(p.color_key)))
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
|
2010-07-02 20:54:56 +00:00
|
|
|
case FBIO_WAITFORVSYNC:
|
|
|
|
if (get_user(p.crt, (__u32 __user *)arg)) {
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (p.crt != 0) {
|
|
|
|
r = -ENODEV;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
case OMAPFB_WAITFORVSYNC:
|
|
|
|
DBG("ioctl WAITFORVSYNC\n");
|
2013-04-23 12:35:35 +00:00
|
|
|
|
|
|
|
if (!display) {
|
2009-08-04 13:12:50 +00:00
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:35:35 +00:00
|
|
|
mgr = omapdss_find_mgr_from_display(display);
|
|
|
|
if (!mgr) {
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2012-09-10 09:13:39 +00:00
|
|
|
|
|
|
|
r = mgr->wait_for_vsync(mgr);
|
2009-08-04 13:12:50 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_WAITFORGO:
|
|
|
|
DBG("ioctl WAITFORGO\n");
|
|
|
|
if (!display) {
|
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = omapfb_wait_for_go(fbi);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* LCD and CTRL tests do the same thing for backward
|
|
|
|
* compatibility */
|
|
|
|
case OMAPFB_LCD_TEST:
|
|
|
|
DBG("ioctl LCD_TEST\n");
|
|
|
|
if (get_user(p.test_num, (int __user *)arg)) {
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
2010-01-08 14:21:28 +00:00
|
|
|
if (!display || !display->driver->run_test) {
|
2009-08-04 13:12:50 +00:00
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-01-08 14:21:28 +00:00
|
|
|
r = display->driver->run_test(display, p.test_num);
|
2009-08-04 13:12:50 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_CTRL_TEST:
|
|
|
|
DBG("ioctl CTRL_TEST\n");
|
|
|
|
if (get_user(p.test_num, (int __user *)arg)) {
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
2010-01-08 14:21:28 +00:00
|
|
|
if (!display || !display->driver->run_test) {
|
2009-08-04 13:12:50 +00:00
|
|
|
r = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-01-08 14:21:28 +00:00
|
|
|
r = display->driver->run_test(display, p.test_num);
|
2009-08-04 13:12:50 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_MEMORY_READ:
|
|
|
|
DBG("ioctl MEMORY_READ\n");
|
|
|
|
|
|
|
|
if (copy_from_user(&p.memory_read, (void __user *)arg,
|
|
|
|
sizeof(p.memory_read))) {
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = omapfb_memory_read(fbi, &p.memory_read);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OMAPFB_GET_VRAM_INFO: {
|
|
|
|
DBG("ioctl GET_VRAM_INFO\n");
|
|
|
|
|
2012-11-09 13:52:20 +00:00
|
|
|
/*
|
|
|
|
* We don't have the ability to get this vram info anymore.
|
|
|
|
* Fill in something that should keep the applications working.
|
|
|
|
*/
|
|
|
|
p.vram_info.total = SZ_1M * 64;
|
|
|
|
p.vram_info.free = SZ_1M * 64;
|
|
|
|
p.vram_info.largest_free_block = SZ_1M * 64;
|
2009-08-04 13:12:50 +00:00
|
|
|
|
|
|
|
if (copy_to_user((void __user *)arg, &p.vram_info,
|
|
|
|
sizeof(p.vram_info)))
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OMAPFB_SET_TEARSYNC: {
|
|
|
|
DBG("ioctl SET_TEARSYNC\n");
|
|
|
|
|
|
|
|
if (copy_from_user(&p.tearsync_info, (void __user *)arg,
|
|
|
|
sizeof(p.tearsync_info))) {
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-06-01 12:12:12 +00:00
|
|
|
if (!display || !display->driver->enable_te) {
|
2009-08-04 13:12:50 +00:00
|
|
|
r = -ENODEV;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-01-11 13:11:01 +00:00
|
|
|
r = display->driver->enable_te(display,
|
|
|
|
!!p.tearsync_info.enabled);
|
2009-08-04 13:12:50 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-01-14 15:32:13 +00:00
|
|
|
case OMAPFB_GET_DISPLAY_INFO: {
|
|
|
|
u16 xres, yres;
|
|
|
|
|
|
|
|
DBG("ioctl GET_DISPLAY_INFO\n");
|
|
|
|
|
|
|
|
if (display == NULL) {
|
|
|
|
r = -ENODEV;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-01-11 11:54:33 +00:00
|
|
|
display->driver->get_resolution(display, &xres, &yres);
|
2010-01-14 15:32:13 +00:00
|
|
|
|
|
|
|
p.display_info.xres = xres;
|
|
|
|
p.display_info.yres = yres;
|
2010-06-16 12:26:36 +00:00
|
|
|
|
|
|
|
if (display->driver->get_dimensions) {
|
|
|
|
u32 w, h;
|
|
|
|
display->driver->get_dimensions(display, &w, &h);
|
|
|
|
p.display_info.width = w;
|
|
|
|
p.display_info.height = h;
|
|
|
|
} else {
|
|
|
|
p.display_info.width = 0;
|
|
|
|
p.display_info.height = 0;
|
|
|
|
}
|
2010-01-14 15:32:13 +00:00
|
|
|
|
|
|
|
if (copy_to_user((void __user *)arg, &p.display_info,
|
|
|
|
sizeof(p.display_info)))
|
|
|
|
r = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-08-04 13:12:50 +00:00
|
|
|
default:
|
|
|
|
dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
|
|
|
|
r = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r < 0)
|
|
|
|
DBG("ioctl failed: %d\n", r);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|