blob: a9ab5c1679e9a1353f4753cc5742ffcb15a96d54 [file] [log] [blame]
/*
* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 1994 Martin Schaller
*
* 2001 - Documented with DocBook
* - Brad Douglas <brad@neruo.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
#include <linux/compat.h>
#include <linux/fb.h>
#include <linux/uaccess.h>
#include "mdss_fb.h"
#include "mdss_compat_utils.h"
#include "mdss_mdp_hwio.h"
#include "mdss_mdp.h"
#define MSMFB_CURSOR32 _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor32)
#define MSMFB_SET_LUT32 _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap32)
#define MSMFB_HISTOGRAM32 _IOWR(MSMFB_IOCTL_MAGIC, 132,\
struct mdp_histogram_data32)
#define MSMFB_GET_CCS_MATRIX32 _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs32)
#define MSMFB_SET_CCS_MATRIX32 _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs32)
#define MSMFB_OVERLAY_SET32 _IOWR(MSMFB_IOCTL_MAGIC, 135,\
struct mdp_overlay32)
#define MSMFB_OVERLAY_GET32 _IOR(MSMFB_IOCTL_MAGIC, 140,\
struct mdp_overlay32)
#define MSMFB_OVERLAY_BLT32 _IOWR(MSMFB_IOCTL_MAGIC, 142,\
struct msmfb_overlay_blt32)
#define MSMFB_HISTOGRAM_START32 _IOR(MSMFB_IOCTL_MAGIC, 144,\
struct mdp_histogram_start_req32)
#define MSMFB_OVERLAY_3D32 _IOWR(MSMFB_IOCTL_MAGIC, 147,\
struct msmfb_overlay_3d32)
#define MSMFB_MIXER_INFO32 _IOWR(MSMFB_IOCTL_MAGIC, 148,\
struct msmfb_mixer_info_req32)
#define MSMFB_MDP_PP32 _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp32)
#define MSMFB_BUFFER_SYNC32 _IOW(MSMFB_IOCTL_MAGIC, 162, struct mdp_buf_sync32)
#define MSMFB_OVERLAY_PREPARE32 _IOWR(MSMFB_IOCTL_MAGIC, 169, \
struct mdp_overlay_list32)
#define MSMFB_ATOMIC_COMMIT32 _IOWR(MDP_IOCTL_MAGIC, 128, compat_caddr_t)
#define MSMFB_ASYNC_POSITION_UPDATE_32 _IOWR(MDP_IOCTL_MAGIC, 129, \
struct mdp_position_update32)
static int __copy_layer_pp_info_params(struct mdp_input_layer *layer,
struct mdp_input_layer32 *layer32);
static unsigned int __do_compat_ioctl_nr(unsigned int cmd32)
{
unsigned int cmd;
switch (cmd32) {
case MSMFB_CURSOR32:
cmd = MSMFB_CURSOR;
break;
case MSMFB_SET_LUT32:
cmd = MSMFB_SET_LUT;
break;
case MSMFB_HISTOGRAM32:
cmd = MSMFB_HISTOGRAM;
break;
case MSMFB_GET_CCS_MATRIX32:
cmd = MSMFB_GET_CCS_MATRIX;
break;
case MSMFB_SET_CCS_MATRIX32:
cmd = MSMFB_SET_CCS_MATRIX;
break;
case MSMFB_OVERLAY_SET32:
cmd = MSMFB_OVERLAY_SET;
break;
case MSMFB_OVERLAY_GET32:
cmd = MSMFB_OVERLAY_GET;
break;
case MSMFB_OVERLAY_BLT32:
cmd = MSMFB_OVERLAY_BLT;
break;
case MSMFB_OVERLAY_3D32:
cmd = MSMFB_OVERLAY_3D;
break;
case MSMFB_MIXER_INFO32:
cmd = MSMFB_MIXER_INFO;
break;
case MSMFB_MDP_PP32:
cmd = MSMFB_MDP_PP;
break;
case MSMFB_BUFFER_SYNC32:
cmd = MSMFB_BUFFER_SYNC;
break;
case MSMFB_OVERLAY_PREPARE32:
cmd = MSMFB_OVERLAY_PREPARE;
break;
case MSMFB_ATOMIC_COMMIT32:
cmd = MSMFB_ATOMIC_COMMIT;
break;
case MSMFB_ASYNC_POSITION_UPDATE_32:
cmd = MSMFB_ASYNC_POSITION_UPDATE;
break;
default:
cmd = cmd32;
break;
}
return cmd;
}
static void __copy_atomic_commit_struct(struct mdp_layer_commit *commit,
struct mdp_layer_commit32 *commit32)
{
commit->version = commit32->version;
commit->commit_v1.flags = commit32->commit_v1.flags;
commit->commit_v1.input_layer_cnt =
commit32->commit_v1.input_layer_cnt;
commit->commit_v1.left_roi = commit32->commit_v1.left_roi;
commit->commit_v1.right_roi = commit32->commit_v1.right_roi;
memcpy(&commit->commit_v1.reserved, &commit32->commit_v1.reserved,
sizeof(commit32->commit_v1.reserved));
}
static struct mdp_input_layer32 *__create_layer_list32(
struct mdp_layer_commit32 *commit32,
u32 layer_count)
{
u32 buffer_size32;
struct mdp_input_layer32 *layer_list32;
int ret;
buffer_size32 = sizeof(struct mdp_input_layer32) * layer_count;
layer_list32 = kmalloc(buffer_size32, GFP_KERNEL);
if (!layer_list32) {
pr_err("unable to allocate memory for layers32\n");
layer_list32 = ERR_PTR(-ENOMEM);
goto end;
}
ret = copy_from_user(layer_list32,
compat_ptr(commit32->commit_v1.input_layers),
sizeof(struct mdp_input_layer32) * layer_count);
if (ret) {
pr_err("layer list32 copy from user failed, ptr %pK\n",
compat_ptr(commit32->commit_v1.input_layers));
kfree(layer_list32);
ret = -EFAULT;
layer_list32 = ERR_PTR(ret);
}
end:
return layer_list32;
}
static int __copy_scale_params(struct mdp_input_layer *layer,
struct mdp_input_layer32 *layer32)
{
struct mdp_scale_data *scale;
int ret;
if (!(layer->flags & MDP_LAYER_ENABLE_PIXEL_EXT))
return 0;
scale = kmalloc(sizeof(struct mdp_scale_data), GFP_KERNEL);
if (!scale) {
pr_err("unable to allocate memory for scale param\n");
ret = -ENOMEM;
goto end;
}
/* scale structure size is same for compat and 64bit version */
ret = copy_from_user(scale, compat_ptr(layer32->scale),
sizeof(struct mdp_scale_data));
if (ret) {
kfree(scale);
pr_err("scale param copy from user failed, ptr %pK\n",
compat_ptr(layer32->scale));
ret = -EFAULT;
} else {
layer->scale = scale;
}
end:
return ret;
}
static struct mdp_input_layer *__create_layer_list(
struct mdp_layer_commit *commit,
struct mdp_input_layer32 *layer_list32,
u32 layer_count)
{
int i, ret;
u32 buffer_size;
struct mdp_input_layer *layer, *layer_list;
struct mdp_input_layer32 *layer32;
buffer_size = sizeof(struct mdp_input_layer) * layer_count;
layer_list = kmalloc(buffer_size, GFP_KERNEL);
if (!layer_list) {
pr_err("unable to allocate memory for layers32\n");
layer_list = ERR_PTR(-ENOMEM);
goto end;
}
commit->commit_v1.input_layers = layer_list;
for (i = 0; i < layer_count; i++) {
layer = &layer_list[i];
layer32 = &layer_list32[i];
layer->flags = layer32->flags;
layer->pipe_ndx = layer32->pipe_ndx;
layer->horz_deci = layer32->horz_deci;
layer->vert_deci = layer32->vert_deci;
layer->z_order = layer32->z_order;
layer->transp_mask = layer32->transp_mask;
layer->bg_color = layer32->bg_color;
layer->blend_op = layer32->blend_op;
layer->src_rect = layer32->src_rect;
layer->dst_rect = layer32->dst_rect;
layer->buffer = layer32->buffer;
memcpy(&layer->reserved, &layer32->reserved,
sizeof(layer->reserved));
layer->scale = NULL;
ret = __copy_scale_params(layer, layer32);
if (ret)
break;
layer->pp_info = NULL;
ret = __copy_layer_pp_info_params(layer, layer32);
if (ret)
break;
}
if (ret) {
for (i--; i >= 0; i--) {
kfree(layer_list[i].scale);
mdss_mdp_free_layer_pp_info(&layer_list[i]);
}
kfree(layer_list);
layer_list = ERR_PTR(ret);
}
end:
return layer_list;
}
static int __copy_to_user_atomic_commit(struct mdp_layer_commit *commit,
struct mdp_layer_commit32 *commit32,
struct mdp_input_layer32 *layer_list32,
unsigned long argp, u32 layer_count)
{
int i, ret;
struct mdp_input_layer *layer_list;
layer_list = commit->commit_v1.input_layers;
for (i = 0; i < layer_count; i++)
layer_list32[i].error_code = layer_list[i].error_code;
ret = copy_to_user(compat_ptr(commit32->commit_v1.input_layers),
layer_list32,
sizeof(struct mdp_input_layer32) * layer_count);
if (ret)
goto end;
ret = copy_to_user(compat_ptr(commit32->commit_v1.output_layer),
commit->commit_v1.output_layer,
sizeof(struct mdp_output_layer));
if (ret)
goto end;
commit32->commit_v1.release_fence =
commit->commit_v1.release_fence;
commit32->commit_v1.retire_fence =
commit->commit_v1.retire_fence;
ret = copy_to_user((void __user *)argp, commit32,
sizeof(struct mdp_layer_commit32));
end:
return ret;
}
static int __compat_atomic_commit(struct fb_info *info, unsigned int cmd,
unsigned long argp, struct file *file)
{
int ret, i;
struct mdp_layer_commit commit;
struct mdp_layer_commit32 commit32;
u32 layer_count;
struct mdp_input_layer *layer_list = NULL;
struct mdp_input_layer32 *layer_list32 = NULL;
struct mdp_output_layer *output_layer = NULL;
/* copy top level memory from 32 bit structure to kernel memory */
ret = copy_from_user(&commit32, (void __user *)argp,
sizeof(struct mdp_layer_commit32));
if (ret) {
pr_err("%s:copy_from_user failed, ptr %pK\n", __func__,
(void __user *)argp);
ret = -EFAULT;
return ret;
}
__copy_atomic_commit_struct(&commit, &commit32);
if (commit32.commit_v1.output_layer) {
int buffer_size = sizeof(struct mdp_output_layer);
output_layer = kzalloc(buffer_size, GFP_KERNEL);
if (!output_layer) {
pr_err("fail to allocate output layer\n");
return -ENOMEM;
}
ret = copy_from_user(output_layer,
compat_ptr(commit32.commit_v1.output_layer),
buffer_size);
if (ret) {
pr_err("fail to copy output layer from user, ptr %pK\n",
compat_ptr(commit32.commit_v1.output_layer));
ret = -EFAULT;
goto layer_list_err;
}
commit.commit_v1.output_layer = output_layer;
}
layer_count = commit32.commit_v1.input_layer_cnt;
if (layer_count > MAX_LAYER_COUNT) {
ret = -EINVAL;
goto layer_list_err;
} else if (layer_count) {
/*
* allocate memory for layer list in 32bit domain and copy it
* from user
*/
layer_list32 = __create_layer_list32(&commit32, layer_count);
if (IS_ERR_OR_NULL(layer_list32)) {
ret = PTR_ERR(layer_list32);
goto layer_list_err;
}
/*
* allocate memory for layer list in kernel memory domain and
* copy layer info from 32bit structures to kernel memory
*/
layer_list = __create_layer_list(&commit, layer_list32,
layer_count);
if (IS_ERR_OR_NULL(layer_list)) {
ret = PTR_ERR(layer_list);
goto layer_list_err;
}
}
ret = mdss_fb_atomic_commit(info, &commit, file);
if (ret)
pr_err("atomic commit failed ret:%d\n", ret);
if (layer_count)
__copy_to_user_atomic_commit(&commit, &commit32, layer_list32,
argp, layer_count);
for (i = 0; i < layer_count; i++) {
kfree(layer_list[i].scale);
mdss_mdp_free_layer_pp_info(&layer_list[i]);
}
kfree(layer_list);
layer_list_err:
kfree(layer_list32);
kfree(output_layer);
return ret;
}
static int __copy_to_user_async_position_update(
struct mdp_position_update *update_pos,
struct mdp_position_update32 *update_pos32,
unsigned long argp, u32 layer_cnt)
{
int ret;
ret = copy_to_user(update_pos32->input_layers,
update_pos->input_layers,
sizeof(struct mdp_async_layer) * layer_cnt);
if (ret)
goto end;
ret = copy_to_user((void __user *) argp, update_pos32,
sizeof(struct mdp_position_update32));
end:
return ret;
}
static struct mdp_async_layer *__create_async_layer_list(
struct mdp_position_update32 *update_pos32, u32 layer_cnt)
{
u32 buffer_size;
struct mdp_async_layer *layer_list;
int ret;
buffer_size = sizeof(struct mdp_async_layer) * layer_cnt;
layer_list = kmalloc(buffer_size, GFP_KERNEL);
if (!layer_list) {
layer_list = ERR_PTR(-ENOMEM);
goto end;
}
ret = copy_from_user(layer_list,
update_pos32->input_layers, buffer_size);
if (ret) {
pr_err("layer list32 copy from user failed\n");
kfree(layer_list);
layer_list = ERR_PTR(ret);
}
end:
return layer_list;
}
static int __compat_async_position_update(struct fb_info *info,
unsigned int cmd, unsigned long argp)
{
struct mdp_position_update update_pos;
struct mdp_position_update32 update_pos32;
struct mdp_async_layer *layer_list = NULL;
u32 layer_cnt, ret;
/* copy top level memory from 32 bit structure to kernel memory */
ret = copy_from_user(&update_pos32, (void __user *)argp,
sizeof(struct mdp_position_update32));
if (ret) {
pr_err("%s:copy_from_user failed\n", __func__);
return ret;
}
update_pos.input_layer_cnt = update_pos32.input_layer_cnt;
layer_cnt = update_pos32.input_layer_cnt;
if ((!layer_cnt) || (layer_cnt > MAX_LAYER_COUNT)) {
pr_err("invalid async layers :%d to update\n", layer_cnt);
return -EINVAL;
}
layer_list = __create_async_layer_list(&update_pos32,
layer_cnt);
if (IS_ERR_OR_NULL(layer_list))
return PTR_ERR(layer_list);
update_pos.input_layers = layer_list;
ret = mdss_fb_async_position_update(info, &update_pos);
if (ret)
pr_err("async position update failed ret:%d\n", ret);
ret = __copy_to_user_async_position_update(&update_pos, &update_pos32,
argp, layer_cnt);
if (ret)
pr_err("copy to user of async update position failed\n");
kfree(layer_list);
return ret;
}
static int mdss_fb_compat_buf_sync(struct fb_info *info, unsigned int cmd,
unsigned long arg, struct file *file)
{
struct mdp_buf_sync32 __user *buf_sync32;
struct mdp_buf_sync __user *buf_sync;
u32 data;
int ret;
buf_sync = compat_alloc_user_space(sizeof(*buf_sync));
if (!buf_sync) {
pr_err("%s:%u: compat alloc error [%zu] bytes\n",
__func__, __LINE__, sizeof(*buf_sync));
return -EINVAL;
}
buf_sync32 = compat_ptr(arg);
if (copy_in_user(&buf_sync->flags, &buf_sync32->flags,
3 * sizeof(u32)))
return -EFAULT;
if (get_user(data, &buf_sync32->acq_fen_fd) ||
put_user(compat_ptr(data), &buf_sync->acq_fen_fd) ||
get_user(data, &buf_sync32->rel_fen_fd) ||
put_user(compat_ptr(data), &buf_sync->rel_fen_fd) ||
get_user(data, &buf_sync32->retire_fen_fd) ||
put_user(compat_ptr(data), &buf_sync->retire_fen_fd))
return -EFAULT;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) buf_sync, file);
if (ret) {
pr_err("%s: failed %d\n", __func__, ret);
return ret;
}
if (copy_in_user(compat_ptr(buf_sync32->rel_fen_fd),
buf_sync->rel_fen_fd,
sizeof(int)))
return -EFAULT;
if (copy_in_user(compat_ptr(buf_sync32->retire_fen_fd),
buf_sync->retire_fen_fd,
sizeof(int))) {
if (buf_sync->flags & MDP_BUF_SYNC_FLAG_RETIRE_FENCE)
return -EFAULT;
else
pr_debug("%s: no retire fence fd for wb\n",
__func__);
}
return ret;
}
static int __from_user_fb_cmap(struct fb_cmap __user *cmap,
struct fb_cmap32 __user *cmap32)
{
__u32 data;
if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
return -EFAULT;
if (get_user(data, &cmap32->red) ||
put_user(compat_ptr(data), &cmap->red) ||
get_user(data, &cmap32->green) ||
put_user(compat_ptr(data), &cmap->green) ||
get_user(data, &cmap32->blue) ||
put_user(compat_ptr(data), &cmap->blue) ||
get_user(data, &cmap32->transp) ||
put_user(compat_ptr(data), &cmap->transp))
return -EFAULT;
return 0;
}
static int __to_user_fb_cmap(struct fb_cmap __user *cmap,
struct fb_cmap32 __user *cmap32)
{
unsigned long data;
if (copy_in_user(&cmap32->start, &cmap->start, 2 * sizeof(__u32)))
return -EFAULT;
if (get_user(data, (unsigned long *) &cmap->red) ||
put_user((compat_caddr_t) data, &cmap32->red) ||
get_user(data, (unsigned long *) &cmap->green) ||
put_user((compat_caddr_t) data, &cmap32->green) ||
get_user(data, (unsigned long *) &cmap->blue) ||
put_user((compat_caddr_t) data, &cmap32->blue) ||
get_user(data, (unsigned long *) &cmap->transp) ||
put_user((compat_caddr_t) data, &cmap32->transp))
return -EFAULT;
return 0;
}
static int __from_user_fb_image(struct fb_image __user *image,
struct fb_image32 __user *image32)
{
__u32 data;
if (copy_in_user(&image->dx, &image32->dx, 6 * sizeof(u32)) ||
copy_in_user(&image->depth, &image32->depth, sizeof(u8)))
return -EFAULT;
if (get_user(data, &image32->data) ||
put_user(compat_ptr(data), &image->data))
return -EFAULT;
if (__from_user_fb_cmap(&image->cmap, &image32->cmap))
return -EFAULT;
return 0;
}
static int mdss_fb_compat_cursor(struct fb_info *info, unsigned int cmd,
unsigned long arg, struct file *file)
{
struct fb_cursor32 __user *cursor32;
struct fb_cursor __user *cursor;
__u32 data;
int ret;
cursor = compat_alloc_user_space(sizeof(*cursor));
if (!cursor) {
pr_err("%s:%u: compat alloc error [%zu] bytes\n",
__func__, __LINE__, sizeof(*cursor));
return -EINVAL;
}
cursor32 = compat_ptr(arg);
if (copy_in_user(&cursor->set, &cursor32->set, 3 * sizeof(u16)))
return -EFAULT;
if (get_user(data, &cursor32->mask) ||
put_user(compat_ptr(data), &cursor->mask))
return -EFAULT;
if (copy_in_user(&cursor->hot, &cursor32->hot, sizeof(struct fbcurpos)))
return -EFAULT;
if (__from_user_fb_image(&cursor->image, &cursor32->image))
return -EFAULT;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) cursor, file);
return ret;
}
static int mdss_fb_compat_set_lut(struct fb_info *info, unsigned long arg,
struct file *file)
{
struct fb_cmap_user __user *cmap;
struct fb_cmap32 __user *cmap32;
__u32 data;
int ret;
cmap = compat_alloc_user_space(sizeof(*cmap));
cmap32 = compat_ptr(arg);
if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
return -EFAULT;
if (get_user(data, &cmap32->red) ||
put_user(compat_ptr(data), &cmap->red) ||
get_user(data, &cmap32->green) ||
put_user(compat_ptr(data), &cmap->green) ||
get_user(data, &cmap32->blue) ||
put_user(compat_ptr(data), &cmap->blue) ||
get_user(data, &cmap32->transp) ||
put_user(compat_ptr(data), &cmap->transp))
return -EFAULT;
ret = mdss_fb_do_ioctl(info, MSMFB_SET_LUT, (unsigned long) cmap, file);
if (!ret)
pr_debug("%s: compat ioctl successful\n", __func__);
return ret;
}
static int __from_user_sharp_cfg(
struct mdp_sharp_cfg32 __user *sharp_cfg32,
struct mdp_sharp_cfg __user *sharp_cfg)
{
if (copy_in_user(&sharp_cfg->flags,
&sharp_cfg32->flags,
sizeof(uint32_t)) ||
copy_in_user(&sharp_cfg->strength,
&sharp_cfg32->strength,
sizeof(uint32_t)) ||
copy_in_user(&sharp_cfg->edge_thr,
&sharp_cfg32->edge_thr,
sizeof(uint32_t)) ||
copy_in_user(&sharp_cfg->smooth_thr,
&sharp_cfg32->smooth_thr,
sizeof(uint32_t)) ||
copy_in_user(&sharp_cfg->noise_thr,
&sharp_cfg32->noise_thr,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __to_user_sharp_cfg(
struct mdp_sharp_cfg32 __user *sharp_cfg32,
struct mdp_sharp_cfg __user *sharp_cfg)
{
if (copy_in_user(&sharp_cfg32->flags,
&sharp_cfg->flags,
sizeof(uint32_t)) ||
copy_in_user(&sharp_cfg32->strength,
&sharp_cfg->strength,
sizeof(uint32_t)) ||
copy_in_user(&sharp_cfg32->edge_thr,
&sharp_cfg->edge_thr,
sizeof(uint32_t)) ||
copy_in_user(&sharp_cfg32->smooth_thr,
&sharp_cfg->smooth_thr,
sizeof(uint32_t)) ||
copy_in_user(&sharp_cfg32->noise_thr,
&sharp_cfg->noise_thr,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_histogram_cfg(
struct mdp_histogram_cfg32 __user *hist_cfg32,
struct mdp_histogram_cfg __user *hist_cfg)
{
if (copy_in_user(&hist_cfg->ops,
&hist_cfg32->ops,
sizeof(uint32_t)) ||
copy_in_user(&hist_cfg->block,
&hist_cfg32->block,
sizeof(uint32_t)) ||
copy_in_user(&hist_cfg->frame_cnt,
&hist_cfg32->frame_cnt,
sizeof(uint8_t)) ||
copy_in_user(&hist_cfg->bit_mask,
&hist_cfg32->bit_mask,
sizeof(uint8_t)) ||
copy_in_user(&hist_cfg->num_bins,
&hist_cfg32->num_bins,
sizeof(uint16_t)))
return -EFAULT;
return 0;
}
static int __to_user_histogram_cfg(
struct mdp_histogram_cfg32 __user *hist_cfg32,
struct mdp_histogram_cfg __user *hist_cfg)
{
if (copy_in_user(&hist_cfg32->ops,
&hist_cfg->ops,
sizeof(uint32_t)) ||
copy_in_user(&hist_cfg32->block,
&hist_cfg->block,
sizeof(uint32_t)) ||
copy_in_user(&hist_cfg32->frame_cnt,
&hist_cfg->frame_cnt,
sizeof(uint8_t)) ||
copy_in_user(&hist_cfg32->bit_mask,
&hist_cfg->bit_mask,
sizeof(uint8_t)) ||
copy_in_user(&hist_cfg32->num_bins,
&hist_cfg->num_bins,
sizeof(uint16_t)))
return -EFAULT;
return 0;
}
static int __from_user_pcc_coeff(
struct mdp_pcc_coeff32 __user *pcc_coeff32,
struct mdp_pcc_coeff __user *pcc_coeff)
{
if (copy_in_user(&pcc_coeff->c,
&pcc_coeff32->c,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->r,
&pcc_coeff32->r,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->g,
&pcc_coeff32->g,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->b,
&pcc_coeff32->b,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->rr,
&pcc_coeff32->rr,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->gg,
&pcc_coeff32->gg,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->bb,
&pcc_coeff32->bb,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->rg,
&pcc_coeff32->rg,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->gb,
&pcc_coeff32->gb,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->rb,
&pcc_coeff32->rb,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->rgb_0,
&pcc_coeff32->rgb_0,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff->rgb_1,
&pcc_coeff32->rgb_1,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __to_user_pcc_coeff(
struct mdp_pcc_coeff32 __user *pcc_coeff32,
struct mdp_pcc_coeff __user *pcc_coeff)
{
if (copy_in_user(&pcc_coeff32->c,
&pcc_coeff->c,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->r,
&pcc_coeff->r,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->g,
&pcc_coeff->g,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->b,
&pcc_coeff->b,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->rr,
&pcc_coeff->rr,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->gg,
&pcc_coeff->gg,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->bb,
&pcc_coeff->bb,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->rg,
&pcc_coeff->rg,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->gb,
&pcc_coeff->gb,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->rb,
&pcc_coeff->rb,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->rgb_0,
&pcc_coeff->rgb_0,
sizeof(uint32_t)) ||
copy_in_user(&pcc_coeff32->rgb_1,
&pcc_coeff->rgb_1,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_pcc_coeff_v17(
struct mdp_pcc_cfg_data32 __user *pcc_cfg32,
struct mdp_pcc_cfg_data __user *pcc_cfg)
{
struct mdp_pcc_data_v1_7_32 pcc_cfg_payload32;
struct mdp_pcc_data_v1_7 pcc_cfg_payload;
if (copy_from_user(&pcc_cfg_payload32,
compat_ptr(pcc_cfg32->cfg_payload),
sizeof(struct mdp_pcc_data_v1_7_32))) {
pr_err("failed to copy payload for pcc from user\n");
return -EFAULT;
}
memset(&pcc_cfg_payload, 0, sizeof(pcc_cfg_payload));
pcc_cfg_payload.r.b = pcc_cfg_payload32.r.b;
pcc_cfg_payload.r.g = pcc_cfg_payload32.r.g;
pcc_cfg_payload.r.c = pcc_cfg_payload32.r.c;
pcc_cfg_payload.r.r = pcc_cfg_payload32.r.r;
pcc_cfg_payload.r.gb = pcc_cfg_payload32.r.gb;
pcc_cfg_payload.r.rb = pcc_cfg_payload32.r.rb;
pcc_cfg_payload.r.rg = pcc_cfg_payload32.r.rg;
pcc_cfg_payload.r.rgb = pcc_cfg_payload32.r.rgb;
pcc_cfg_payload.g.b = pcc_cfg_payload32.g.b;
pcc_cfg_payload.g.g = pcc_cfg_payload32.g.g;
pcc_cfg_payload.g.c = pcc_cfg_payload32.g.c;
pcc_cfg_payload.g.r = pcc_cfg_payload32.g.r;
pcc_cfg_payload.g.gb = pcc_cfg_payload32.g.gb;
pcc_cfg_payload.g.rb = pcc_cfg_payload32.g.rb;
pcc_cfg_payload.g.rg = pcc_cfg_payload32.g.rg;
pcc_cfg_payload.g.rgb = pcc_cfg_payload32.g.rgb;
pcc_cfg_payload.b.b = pcc_cfg_payload32.b.b;
pcc_cfg_payload.b.g = pcc_cfg_payload32.b.g;
pcc_cfg_payload.b.c = pcc_cfg_payload32.b.c;
pcc_cfg_payload.b.r = pcc_cfg_payload32.b.r;
pcc_cfg_payload.b.gb = pcc_cfg_payload32.b.gb;
pcc_cfg_payload.b.rb = pcc_cfg_payload32.b.rb;
pcc_cfg_payload.b.rg = pcc_cfg_payload32.b.rg;
pcc_cfg_payload.b.rgb = pcc_cfg_payload32.b.rgb;
if (copy_to_user(pcc_cfg->cfg_payload, &pcc_cfg_payload,
sizeof(pcc_cfg_payload))) {
pr_err("failed to copy payload for pcc to user\n");
return -EFAULT;
}
return 0;
}
static int __from_user_pcc_cfg_data(
struct mdp_pcc_cfg_data32 __user *pcc_cfg32,
struct mdp_pcc_cfg_data __user *pcc_cfg)
{
u32 version;
if (copy_in_user(&pcc_cfg->block,
&pcc_cfg32->block,
sizeof(uint32_t)) ||
copy_in_user(&pcc_cfg->ops,
&pcc_cfg32->ops,
sizeof(uint32_t)) ||
copy_in_user(&pcc_cfg->version,
&pcc_cfg32->version,
sizeof(uint32_t)))
return -EFAULT;
if (copy_from_user(&version, &pcc_cfg32->version, sizeof(u32))) {
pr_err("failed to copy version for pcc\n");
return -EFAULT;
}
switch (version) {
case mdp_pcc_v1_7:
if (__from_user_pcc_coeff_v17(pcc_cfg32, pcc_cfg)) {
pr_err("failed to copy pcc v17 data\n");
return -EFAULT;
}
break;
default:
pr_debug("pcc version %d not supported use legacy\n", version);
if (__from_user_pcc_coeff(
compat_ptr((uintptr_t)&pcc_cfg32->r),
&pcc_cfg->r) ||
__from_user_pcc_coeff(
compat_ptr((uintptr_t)&pcc_cfg32->g),
&pcc_cfg->g) ||
__from_user_pcc_coeff(
compat_ptr((uintptr_t)&pcc_cfg32->b),
&pcc_cfg->b))
return -EFAULT;
break;
}
return 0;
}
static int __to_user_pcc_coeff_v1_7(
struct mdp_pcc_cfg_data32 __user *pcc_cfg32,
struct mdp_pcc_cfg_data __user *pcc_cfg)
{
struct mdp_pcc_data_v1_7_32 pcc_cfg_payload32;
struct mdp_pcc_data_v1_7 pcc_cfg_payload;
if (copy_from_user(&pcc_cfg_payload,
pcc_cfg->cfg_payload,
sizeof(struct mdp_pcc_data_v1_7))) {
pr_err("failed to copy payload for pcc from user\n");
return -EFAULT;
}
pcc_cfg_payload32.r.b = pcc_cfg_payload.r.b;
pcc_cfg_payload32.r.g = pcc_cfg_payload.r.g;
pcc_cfg_payload32.r.c = pcc_cfg_payload.r.c;
pcc_cfg_payload32.r.r = pcc_cfg_payload.r.r;
pcc_cfg_payload32.r.gb = pcc_cfg_payload.r.gb;
pcc_cfg_payload32.r.rb = pcc_cfg_payload.r.rb;
pcc_cfg_payload32.r.rg = pcc_cfg_payload.r.rg;
pcc_cfg_payload32.r.rgb = pcc_cfg_payload.r.rgb;
pcc_cfg_payload32.g.b = pcc_cfg_payload.g.b;
pcc_cfg_payload32.g.g = pcc_cfg_payload.g.g;
pcc_cfg_payload32.g.c = pcc_cfg_payload.g.c;
pcc_cfg_payload32.g.r = pcc_cfg_payload.g.r;
pcc_cfg_payload32.g.gb = pcc_cfg_payload.g.gb;
pcc_cfg_payload32.g.rb = pcc_cfg_payload.g.rb;
pcc_cfg_payload32.g.rg = pcc_cfg_payload.g.rg;
pcc_cfg_payload32.g.rgb = pcc_cfg_payload.g.rgb;
pcc_cfg_payload32.b.b = pcc_cfg_payload.b.b;
pcc_cfg_payload32.b.g = pcc_cfg_payload.b.g;
pcc_cfg_payload32.b.c = pcc_cfg_payload.b.c;
pcc_cfg_payload32.b.r = pcc_cfg_payload.b.r;
pcc_cfg_payload32.b.gb = pcc_cfg_payload.b.gb;
pcc_cfg_payload32.b.rb = pcc_cfg_payload.b.rb;
pcc_cfg_payload32.b.rg = pcc_cfg_payload.b.rg;
pcc_cfg_payload32.b.rgb = pcc_cfg_payload.b.rgb;
if (copy_to_user(compat_ptr(pcc_cfg32->cfg_payload),
&pcc_cfg_payload32,
sizeof(pcc_cfg_payload32))) {
pr_err("failed to copy payload for pcc to user\n");
return -EFAULT;
}
return 0;
}
static int __to_user_pcc_cfg_data(
struct mdp_pcc_cfg_data32 __user *pcc_cfg32,
struct mdp_pcc_cfg_data __user *pcc_cfg)
{
u32 version;
u32 ops;
if (copy_from_user(&ops, &pcc_cfg->ops, sizeof(u32))) {
pr_err("failed to copy op for pcc\n");
return -EFAULT;
}
if (!(ops & MDP_PP_OPS_READ)) {
pr_debug("Read op is not set. Skipping compat copyback\n");
return 0;
}
if (copy_from_user(&version, &pcc_cfg->version, sizeof(u32))) {
pr_err("failed to copy version for pcc\n");
return -EFAULT;
}
switch (version) {
case mdp_pcc_v1_7:
if (__to_user_pcc_coeff_v1_7(pcc_cfg32, pcc_cfg)) {
pr_err("failed to copy pcc v1_7 data\n");
return -EFAULT;
}
break;
default:
pr_debug("version invalid, fallback to legacy\n");
if (__to_user_pcc_coeff(
compat_ptr((uintptr_t)&pcc_cfg32->r),
&pcc_cfg->r) ||
__to_user_pcc_coeff(
compat_ptr((uintptr_t)&pcc_cfg32->g),
&pcc_cfg->g) ||
__to_user_pcc_coeff(
compat_ptr((uintptr_t)&pcc_cfg32->b),
&pcc_cfg->b))
return -EFAULT;
break;
}
return 0;
}
static int __from_user_csc_cfg(
struct mdp_csc_cfg32 __user *csc_data32,
struct mdp_csc_cfg __user *csc_data)
{
if (copy_in_user(&csc_data->flags,
&csc_data32->flags,
sizeof(uint32_t)) ||
copy_in_user(&csc_data->csc_mv[0],
&csc_data32->csc_mv[0],
9 * sizeof(uint32_t)) ||
copy_in_user(&csc_data->csc_pre_bv[0],
&csc_data32->csc_pre_bv[0],
3 * sizeof(uint32_t)) ||
copy_in_user(&csc_data->csc_post_bv[0],
&csc_data32->csc_post_bv[0],
3 * sizeof(uint32_t)) ||
copy_in_user(&csc_data->csc_pre_lv[0],
&csc_data32->csc_pre_lv[0],
6 * sizeof(uint32_t)) ||
copy_in_user(&csc_data->csc_post_lv[0],
&csc_data32->csc_post_lv[0],
6 * sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __to_user_csc_cfg(
struct mdp_csc_cfg32 __user *csc_data32,
struct mdp_csc_cfg __user *csc_data)
{
if (copy_in_user(&csc_data32->flags,
&csc_data->flags,
sizeof(uint32_t)) ||
copy_in_user(&csc_data32->csc_mv[0],
&csc_data->csc_mv[0],
9 * sizeof(uint32_t)) ||
copy_in_user(&csc_data32->csc_pre_bv[0],
&csc_data->csc_pre_bv[0],
3 * sizeof(uint32_t)) ||
copy_in_user(&csc_data32->csc_post_bv[0],
&csc_data->csc_post_bv[0],
3 * sizeof(uint32_t)) ||
copy_in_user(&csc_data32->csc_pre_lv[0],
&csc_data->csc_pre_lv[0],
6 * sizeof(uint32_t)) ||
copy_in_user(&csc_data32->csc_post_lv[0],
&csc_data->csc_post_lv[0],
6 * sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_csc_cfg_data(
struct mdp_csc_cfg_data32 __user *csc_cfg32,
struct mdp_csc_cfg_data __user *csc_cfg)
{
if (copy_in_user(&csc_cfg->block,
&csc_cfg32->block,
sizeof(uint32_t)))
return -EFAULT;
if (__from_user_csc_cfg(
compat_ptr((uintptr_t)&csc_cfg32->csc_data),
&csc_cfg->csc_data))
return -EFAULT;
return 0;
}
static int __to_user_csc_cfg_data(
struct mdp_csc_cfg_data32 __user *csc_cfg32,
struct mdp_csc_cfg_data __user *csc_cfg)
{
if (copy_in_user(&csc_cfg32->block,
&csc_cfg->block,
sizeof(uint32_t)))
return -EFAULT;
if (__to_user_csc_cfg(
compat_ptr((uintptr_t)&csc_cfg32->csc_data),
&csc_cfg->csc_data))
return -EFAULT;
return 0;
}
static int __from_user_igc_lut_data_v17(
struct mdp_igc_lut_data32 __user *igc_lut32,
struct mdp_igc_lut_data __user *igc_lut)
{
struct mdp_igc_lut_data_v1_7_32 igc_cfg_payload_32;
struct mdp_igc_lut_data_v1_7 igc_cfg_payload;
if (copy_from_user(&igc_cfg_payload_32,
compat_ptr(igc_lut32->cfg_payload),
sizeof(igc_cfg_payload_32))) {
pr_err("failed to copy payload from user for igc\n");
return -EFAULT;
}
memset(&igc_cfg_payload, 0, sizeof(igc_cfg_payload));
igc_cfg_payload.c0_c1_data = compat_ptr(igc_cfg_payload_32.c0_c1_data);
igc_cfg_payload.c2_data = compat_ptr(igc_cfg_payload_32.c2_data);
igc_cfg_payload.len = igc_cfg_payload_32.len;
igc_cfg_payload.table_fmt = igc_cfg_payload_32.table_fmt;
if (copy_to_user(igc_lut->cfg_payload, &igc_cfg_payload,
sizeof(igc_cfg_payload))) {
pr_err("failed to copy payload to user for igc\n");
return -EFAULT;
}
return 0;
}
static int __from_user_igc_lut_data(
struct mdp_igc_lut_data32 __user *igc_lut32,
struct mdp_igc_lut_data __user *igc_lut)
{
uint32_t data;
uint32_t version = mdp_igc_vmax;
int ret = 0;
if (copy_in_user(&igc_lut->block,
&igc_lut32->block,
sizeof(uint32_t)) ||
copy_in_user(&igc_lut->len,
&igc_lut32->len,
sizeof(uint32_t)) ||
copy_in_user(&igc_lut->ops,
&igc_lut32->ops,
sizeof(uint32_t)) ||
copy_in_user(&igc_lut->version,
&igc_lut32->version,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(version, &igc_lut32->version)) {
pr_err("failed to copy the version for IGC\n");
return -EFAULT;
}
switch (version) {
case mdp_igc_v1_7:
ret = __from_user_igc_lut_data_v17(igc_lut32, igc_lut);
if (ret)
pr_err("failed to copy payload for igc version %d ret %d\n",
version, ret);
break;
default:
pr_debug("version not supported fallback to legacy %d\n",
version);
if (get_user(data, &igc_lut32->c0_c1_data) ||
put_user(compat_ptr(data), &igc_lut->c0_c1_data) ||
get_user(data, &igc_lut32->c2_data) ||
put_user(compat_ptr(data), &igc_lut->c2_data))
return -EFAULT;
break;
}
return ret;
}
static int __to_user_igc_lut_data(
struct mdp_igc_lut_data32 __user *igc_lut32,
struct mdp_igc_lut_data __user *igc_lut)
{
unsigned long data;
if (copy_in_user(&igc_lut32->block,
&igc_lut->block,
sizeof(uint32_t)) ||
copy_in_user(&igc_lut32->len,
&igc_lut->len,
sizeof(uint32_t)) ||
copy_in_user(&igc_lut32->ops,
&igc_lut->ops,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, (unsigned long *) &igc_lut->c0_c1_data) ||
put_user((compat_caddr_t) data, &igc_lut32->c0_c1_data) ||
get_user(data, (unsigned long *) &igc_lut->c2_data) ||
put_user((compat_caddr_t) data, &igc_lut32->c2_data))
return -EFAULT;
return 0;
}
static int __from_user_ar_gc_lut_data(
struct mdp_ar_gc_lut_data32 __user *ar_gc_data32,
struct mdp_ar_gc_lut_data __user *ar_gc_data)
{
if (copy_in_user(&ar_gc_data->x_start,
&ar_gc_data32->x_start,
sizeof(uint32_t)) ||
copy_in_user(&ar_gc_data->slope,
&ar_gc_data32->slope,
sizeof(uint32_t)) ||
copy_in_user(&ar_gc_data->offset,
&ar_gc_data32->offset,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __to_user_ar_gc_lut_data(
struct mdp_ar_gc_lut_data32 __user *ar_gc_data32,
struct mdp_ar_gc_lut_data __user *ar_gc_data)
{
if (copy_in_user(&ar_gc_data32->x_start,
&ar_gc_data->x_start,
sizeof(uint32_t)) ||
copy_in_user(&ar_gc_data32->slope,
&ar_gc_data->slope,
sizeof(uint32_t)) ||
copy_in_user(&ar_gc_data32->offset,
&ar_gc_data->offset,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_pgc_lut_data_v1_7(
struct mdp_pgc_lut_data32 __user *pgc_lut32,
struct mdp_pgc_lut_data __user *pgc_lut)
{
struct mdp_pgc_lut_data_v1_7_32 pgc_cfg_payload_32;
struct mdp_pgc_lut_data_v1_7 pgc_cfg_payload;
if (copy_from_user(&pgc_cfg_payload_32,
compat_ptr(pgc_lut32->cfg_payload),
sizeof(pgc_cfg_payload_32))) {
pr_err("failed to copy from user the pgc32 payload\n");
return -EFAULT;
}
memset(&pgc_cfg_payload, 0, sizeof(pgc_cfg_payload));
pgc_cfg_payload.c0_data = compat_ptr(pgc_cfg_payload_32.c0_data);
pgc_cfg_payload.c1_data = compat_ptr(pgc_cfg_payload_32.c1_data);
pgc_cfg_payload.c2_data = compat_ptr(pgc_cfg_payload_32.c2_data);
pgc_cfg_payload.len = pgc_cfg_payload_32.len;
if (copy_to_user(pgc_lut->cfg_payload, &pgc_cfg_payload,
sizeof(pgc_cfg_payload))) {
pr_err("failed to copy to user pgc payload\n");
return -EFAULT;
}
return 0;
}
static int __from_user_pgc_lut_data_legacy(
struct mdp_pgc_lut_data32 __user *pgc_lut32,
struct mdp_pgc_lut_data __user *pgc_lut)
{
struct mdp_ar_gc_lut_data32 __user *r_data_temp32;
struct mdp_ar_gc_lut_data32 __user *g_data_temp32;
struct mdp_ar_gc_lut_data32 __user *b_data_temp32;
struct mdp_ar_gc_lut_data __user *r_data_temp;
struct mdp_ar_gc_lut_data __user *g_data_temp;
struct mdp_ar_gc_lut_data __user *b_data_temp;
uint8_t num_r_stages, num_g_stages, num_b_stages;
int i;
if (copy_from_user(&num_r_stages,
&pgc_lut32->num_r_stages,
sizeof(uint8_t)) ||
copy_from_user(&num_g_stages,
&pgc_lut32->num_g_stages,
sizeof(uint8_t)) ||
copy_from_user(&num_b_stages,
&pgc_lut32->num_b_stages,
sizeof(uint8_t)))
return -EFAULT;
if (num_r_stages > GC_LUT_SEGMENTS || num_b_stages > GC_LUT_SEGMENTS
|| num_r_stages > GC_LUT_SEGMENTS || !num_r_stages || !num_b_stages
|| !num_g_stages) {
pr_err("invalid number of stages r_stages %d b_stages %d g_stages %d\n",
num_r_stages, num_b_stages, num_r_stages);
return -EFAULT;
}
r_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->r_data);
r_data_temp = pgc_lut->r_data;
for (i = 0; i < num_r_stages; i++) {
if (__from_user_ar_gc_lut_data(
&r_data_temp32[i],
&r_data_temp[i]))
return -EFAULT;
}
g_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->g_data);
g_data_temp = pgc_lut->g_data;
for (i = 0; i < num_g_stages; i++) {
if (__from_user_ar_gc_lut_data(
&g_data_temp32[i],
&g_data_temp[i]))
return -EFAULT;
}
b_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->b_data);
b_data_temp = pgc_lut->b_data;
for (i = 0; i < num_b_stages; i++) {
if (__from_user_ar_gc_lut_data(
&b_data_temp32[i],
&b_data_temp[i]))
return -EFAULT;
}
return 0;
}
static int __from_user_pgc_lut_data(
struct mdp_pgc_lut_data32 __user *pgc_lut32,
struct mdp_pgc_lut_data __user *pgc_lut)
{
u32 version = mdp_pgc_vmax;
int ret = 0;
if (copy_in_user(&pgc_lut->block,
&pgc_lut32->block,
sizeof(uint32_t)) ||
copy_in_user(&pgc_lut->flags,
&pgc_lut32->flags,
sizeof(uint32_t)) ||
copy_in_user(&pgc_lut->num_r_stages,
&pgc_lut32->num_r_stages,
sizeof(uint8_t)) ||
copy_in_user(&pgc_lut->num_g_stages,
&pgc_lut32->num_g_stages,
sizeof(uint8_t)) ||
copy_in_user(&pgc_lut->num_b_stages,
&pgc_lut32->num_b_stages,
sizeof(uint8_t)) ||
copy_in_user(&pgc_lut->version,
&pgc_lut32->version,
sizeof(uint32_t)))
return -EFAULT;
if (copy_from_user(&version, &pgc_lut32->version, sizeof(u32))) {
pr_err("version copying failed\n");
return -EFAULT;
}
switch (version) {
case mdp_pgc_v1_7:
ret = __from_user_pgc_lut_data_v1_7(pgc_lut32, pgc_lut);
if (ret)
pr_err("failed to copy pgc v17\n");
break;
default:
pr_debug("version %d not supported fallback to legacy\n",
version);
ret = __from_user_pgc_lut_data_legacy(pgc_lut32, pgc_lut);
if (ret)
pr_err("copy from user pgc lut legacy failed ret %d\n",
ret);
break;
}
return ret;
}
static int __to_user_pgc_lut_data(
struct mdp_pgc_lut_data32 __user *pgc_lut32,
struct mdp_pgc_lut_data __user *pgc_lut)
{
struct mdp_ar_gc_lut_data32 __user *r_data_temp32;
struct mdp_ar_gc_lut_data32 __user *g_data_temp32;
struct mdp_ar_gc_lut_data32 __user *b_data_temp32;
struct mdp_ar_gc_lut_data __user *r_data_temp;
struct mdp_ar_gc_lut_data __user *g_data_temp;
struct mdp_ar_gc_lut_data __user *b_data_temp;
uint8_t num_r_stages, num_g_stages, num_b_stages;
int i;
if (copy_in_user(&pgc_lut32->block,
&pgc_lut->block,
sizeof(uint32_t)) ||
copy_in_user(&pgc_lut32->flags,
&pgc_lut->flags,
sizeof(uint32_t)) ||
copy_in_user(&pgc_lut32->num_r_stages,
&pgc_lut->num_r_stages,
sizeof(uint8_t)) ||
copy_in_user(&pgc_lut32->num_g_stages,
&pgc_lut->num_g_stages,
sizeof(uint8_t)) ||
copy_in_user(&pgc_lut32->num_b_stages,
&pgc_lut->num_b_stages,
sizeof(uint8_t)))
return -EFAULT;
if (copy_from_user(&num_r_stages,
&pgc_lut->num_r_stages,
sizeof(uint8_t)) ||
copy_from_user(&num_g_stages,
&pgc_lut->num_g_stages,
sizeof(uint8_t)) ||
copy_from_user(&num_b_stages,
&pgc_lut->num_b_stages,
sizeof(uint8_t)))
return -EFAULT;
r_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->r_data);
r_data_temp = pgc_lut->r_data;
for (i = 0; i < num_r_stages; i++) {
if (__to_user_ar_gc_lut_data(
&r_data_temp32[i],
&r_data_temp[i]))
return -EFAULT;
}
g_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->g_data);
g_data_temp = pgc_lut->g_data;
for (i = 0; i < num_g_stages; i++) {
if (__to_user_ar_gc_lut_data(
&g_data_temp32[i],
&g_data_temp[i]))
return -EFAULT;
}
b_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->b_data);
b_data_temp = pgc_lut->b_data;
for (i = 0; i < num_b_stages; i++) {
if (__to_user_ar_gc_lut_data(
&b_data_temp32[i],
&b_data_temp[i]))
return -EFAULT;
}
return 0;
}
static int __from_user_hist_lut_data_v1_7(
struct mdp_hist_lut_data32 __user *hist_lut32,
struct mdp_hist_lut_data __user *hist_lut)
{
struct mdp_hist_lut_data_v1_7_32 hist_lut_cfg_payload32;
struct mdp_hist_lut_data_v1_7 hist_lut_cfg_payload;
if (copy_from_user(&hist_lut_cfg_payload32,
compat_ptr(hist_lut32->cfg_payload),
sizeof(hist_lut_cfg_payload32))) {
pr_err("failed to copy the Hist Lut payload from userspace\n");
return -EFAULT;
}
memset(&hist_lut_cfg_payload, 0, sizeof(hist_lut_cfg_payload));
hist_lut_cfg_payload.len = hist_lut_cfg_payload32.len;
hist_lut_cfg_payload.data = compat_ptr(hist_lut_cfg_payload32.data);
if (copy_to_user(hist_lut->cfg_payload,
&hist_lut_cfg_payload,
sizeof(hist_lut_cfg_payload))) {
pr_err("Failed to copy to user hist lut cfg payload\n");
return -EFAULT;
}
return 0;
}
static int __from_user_hist_lut_data(
struct mdp_hist_lut_data32 __user *hist_lut32,
struct mdp_hist_lut_data __user *hist_lut)
{
uint32_t version = 0;
uint32_t data;
if (copy_in_user(&hist_lut->block,
&hist_lut32->block,
sizeof(uint32_t)) ||
copy_in_user(&hist_lut->version,
&hist_lut32->version,
sizeof(uint32_t)) ||
copy_in_user(&hist_lut->hist_lut_first,
&hist_lut32->hist_lut_first,
sizeof(uint32_t)) ||
copy_in_user(&hist_lut->ops,
&hist_lut32->ops,
sizeof(uint32_t)) ||
copy_in_user(&hist_lut->len,
&hist_lut32->len,
sizeof(uint32_t)))
return -EFAULT;
if (copy_from_user(&version,
&hist_lut32->version,
sizeof(uint32_t))) {
pr_err("failed to copy the version info\n");
return -EFAULT;
}
switch (version) {
case mdp_hist_lut_v1_7:
if (__from_user_hist_lut_data_v1_7(hist_lut32, hist_lut)) {
pr_err("failed to get hist lut data for version %d\n",
version);
return -EFAULT;
}
break;
default:
pr_debug("version invalid, fallback to legacy\n");
if (get_user(data, &hist_lut32->data) ||
put_user(compat_ptr(data), &hist_lut->data))
return -EFAULT;
break;
}
return 0;
}
static int __to_user_hist_lut_data(
struct mdp_hist_lut_data32 __user *hist_lut32,
struct mdp_hist_lut_data __user *hist_lut)
{
unsigned long data;
if (copy_in_user(&hist_lut32->block,
&hist_lut->block,
sizeof(uint32_t)) ||
copy_in_user(&hist_lut32->ops,
&hist_lut->ops,
sizeof(uint32_t)) ||
copy_in_user(&hist_lut32->len,
&hist_lut->len,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, (unsigned long *) &hist_lut->data) ||
put_user((compat_caddr_t) data, &hist_lut32->data))
return -EFAULT;
return 0;
}
static int __from_user_rgb_lut_data(
struct mdp_rgb_lut_data32 __user *rgb_lut32,
struct mdp_rgb_lut_data __user *rgb_lut)
{
if (copy_in_user(&rgb_lut->flags, &rgb_lut32->flags,
sizeof(uint32_t)) ||
copy_in_user(&rgb_lut->lut_type, &rgb_lut32->lut_type,
sizeof(uint32_t)))
return -EFAULT;
return __from_user_fb_cmap(&rgb_lut->cmap, &rgb_lut32->cmap);
}
static int __to_user_rgb_lut_data(
struct mdp_rgb_lut_data32 __user *rgb_lut32,
struct mdp_rgb_lut_data __user *rgb_lut)
{
if (copy_in_user(&rgb_lut32->flags, &rgb_lut->flags,
sizeof(uint32_t)) ||
copy_in_user(&rgb_lut32->lut_type, &rgb_lut->lut_type,
sizeof(uint32_t)))
return -EFAULT;
return __to_user_fb_cmap(&rgb_lut->cmap, &rgb_lut32->cmap);
}
static int __from_user_lut_cfg_data(
struct mdp_lut_cfg_data32 __user *lut_cfg32,
struct mdp_lut_cfg_data __user *lut_cfg)
{
uint32_t lut_type;
int ret = 0;
if (copy_from_user(&lut_type, &lut_cfg32->lut_type,
sizeof(uint32_t)))
return -EFAULT;
if (copy_in_user(&lut_cfg->lut_type,
&lut_cfg32->lut_type,
sizeof(uint32_t)))
return -EFAULT;
switch (lut_type) {
case mdp_lut_igc:
ret = __from_user_igc_lut_data(
compat_ptr((uintptr_t)&lut_cfg32->data.igc_lut_data),
&lut_cfg->data.igc_lut_data);
break;
case mdp_lut_pgc:
ret = __from_user_pgc_lut_data(
compat_ptr((uintptr_t)&lut_cfg32->data.pgc_lut_data),
&lut_cfg->data.pgc_lut_data);
break;
case mdp_lut_hist:
ret = __from_user_hist_lut_data(
compat_ptr((uintptr_t)&lut_cfg32->data.hist_lut_data),
&lut_cfg->data.hist_lut_data);
break;
case mdp_lut_rgb:
ret = __from_user_rgb_lut_data(
compat_ptr((uintptr_t)&lut_cfg32->data.rgb_lut_data),
&lut_cfg->data.rgb_lut_data);
break;
default:
break;
}
return ret;
}
static int __to_user_lut_cfg_data(
struct mdp_lut_cfg_data32 __user *lut_cfg32,
struct mdp_lut_cfg_data __user *lut_cfg)
{
uint32_t lut_type;
int ret = 0;
if (copy_from_user(&lut_type, &lut_cfg->lut_type,
sizeof(uint32_t)))
return -EFAULT;
if (copy_in_user(&lut_cfg32->lut_type,
&lut_cfg->lut_type,
sizeof(uint32_t)))
return -EFAULT;
switch (lut_type) {
case mdp_lut_igc:
ret = __to_user_igc_lut_data(
compat_ptr((uintptr_t)&lut_cfg32->data.igc_lut_data),
&lut_cfg->data.igc_lut_data);
break;
case mdp_lut_pgc:
ret = __to_user_pgc_lut_data(
compat_ptr((uintptr_t)&lut_cfg32->data.pgc_lut_data),
&lut_cfg->data.pgc_lut_data);
break;
case mdp_lut_hist:
ret = __to_user_hist_lut_data(
compat_ptr((uintptr_t)&lut_cfg32->data.hist_lut_data),
&lut_cfg->data.hist_lut_data);
break;
case mdp_lut_rgb:
ret = __to_user_rgb_lut_data(
compat_ptr((uintptr_t)&lut_cfg32->data.rgb_lut_data),
&lut_cfg->data.rgb_lut_data);
break;
default:
break;
}
return ret;
}
static int __from_user_qseed_cfg(
struct mdp_qseed_cfg32 __user *qseed_data32,
struct mdp_qseed_cfg __user *qseed_data)
{
uint32_t data;
if (copy_in_user(&qseed_data->table_num,
&qseed_data32->table_num,
sizeof(uint32_t)) ||
copy_in_user(&qseed_data->ops,
&qseed_data32->ops,
sizeof(uint32_t)) ||
copy_in_user(&qseed_data->len,
&qseed_data32->len,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, &qseed_data32->data) ||
put_user(compat_ptr(data), &qseed_data->data))
return -EFAULT;
return 0;
}
static int __to_user_qseed_cfg(
struct mdp_qseed_cfg32 __user *qseed_data32,
struct mdp_qseed_cfg __user *qseed_data)
{
unsigned long data;
if (copy_in_user(&qseed_data32->table_num,
&qseed_data->table_num,
sizeof(uint32_t)) ||
copy_in_user(&qseed_data32->ops,
&qseed_data->ops,
sizeof(uint32_t)) ||
copy_in_user(&qseed_data32->len,
&qseed_data->len,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, (unsigned long *) &qseed_data->data) ||
put_user((compat_caddr_t) data, &qseed_data32->data))
return -EFAULT;
return 0;
}
static int __from_user_qseed_cfg_data(
struct mdp_qseed_cfg_data32 __user *qseed_cfg32,
struct mdp_qseed_cfg_data __user *qseed_cfg)
{
if (copy_in_user(&qseed_cfg->block,
&qseed_cfg32->block,
sizeof(uint32_t)))
return -EFAULT;
if (__from_user_qseed_cfg(
compat_ptr((uintptr_t)&qseed_cfg32->qseed_data),
&qseed_cfg->qseed_data))
return -EFAULT;
return 0;
}
static int __to_user_qseed_cfg_data(
struct mdp_qseed_cfg_data32 __user *qseed_cfg32,
struct mdp_qseed_cfg_data __user *qseed_cfg)
{
if (copy_in_user(&qseed_cfg32->block,
&qseed_cfg->block,
sizeof(uint32_t)))
return -EFAULT;
if (__to_user_qseed_cfg(
compat_ptr((uintptr_t)&qseed_cfg32->qseed_data),
&qseed_cfg->qseed_data))
return -EFAULT;
return 0;
}
static int __from_user_bl_scale_data(
struct mdp_bl_scale_data32 __user *bl_scale32,
struct mdp_bl_scale_data __user *bl_scale)
{
if (copy_in_user(&bl_scale->min_lvl,
&bl_scale32->min_lvl,
sizeof(uint32_t)) ||
copy_in_user(&bl_scale->scale,
&bl_scale32->scale,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_pa_cfg(
struct mdp_pa_cfg32 __user *pa_data32,
struct mdp_pa_cfg __user *pa_data)
{
if (copy_in_user(&pa_data->flags,
&pa_data32->flags,
sizeof(uint32_t)) ||
copy_in_user(&pa_data->hue_adj,
&pa_data32->hue_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_data->sat_adj,
&pa_data32->sat_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_data->val_adj,
&pa_data32->val_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_data->cont_adj,
&pa_data32->cont_adj,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __to_user_pa_cfg(
struct mdp_pa_cfg32 __user *pa_data32,
struct mdp_pa_cfg __user *pa_data)
{
if (copy_in_user(&pa_data32->flags,
&pa_data->flags,
sizeof(uint32_t)) ||
copy_in_user(&pa_data32->hue_adj,
&pa_data->hue_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_data32->sat_adj,
&pa_data->sat_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_data32->val_adj,
&pa_data->val_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_data32->cont_adj,
&pa_data->cont_adj,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_pa_cfg_data(
struct mdp_pa_cfg_data32 __user *pa_cfg32,
struct mdp_pa_cfg_data __user *pa_cfg)
{
if (copy_in_user(&pa_cfg->block,
&pa_cfg32->block,
sizeof(uint32_t)))
return -EFAULT;
if (__from_user_pa_cfg(
compat_ptr((uintptr_t)&pa_cfg32->pa_data),
&pa_cfg->pa_data))
return -EFAULT;
return 0;
}
static int __to_user_pa_cfg_data(
struct mdp_pa_cfg_data32 __user *pa_cfg32,
struct mdp_pa_cfg_data __user *pa_cfg)
{
if (copy_in_user(&pa_cfg32->block,
&pa_cfg->block,
sizeof(uint32_t)))
return -EFAULT;
if (__to_user_pa_cfg(
compat_ptr((uintptr_t)&pa_cfg32->pa_data),
&pa_cfg->pa_data))
return -EFAULT;
return 0;
}
static int __from_user_mem_col_cfg(
struct mdp_pa_mem_col_cfg32 __user *mem_col_cfg32,
struct mdp_pa_mem_col_cfg __user *mem_col_cfg)
{
if (copy_in_user(&mem_col_cfg->color_adjust_p0,
&mem_col_cfg32->color_adjust_p0,
sizeof(uint32_t)) ||
copy_in_user(&mem_col_cfg->color_adjust_p1,
&mem_col_cfg32->color_adjust_p1,
sizeof(uint32_t)) ||
copy_in_user(&mem_col_cfg->hue_region,
&mem_col_cfg32->hue_region,
sizeof(uint32_t)) ||
copy_in_user(&mem_col_cfg->sat_region,
&mem_col_cfg32->sat_region,
sizeof(uint32_t)) ||
copy_in_user(&mem_col_cfg->val_region,
&mem_col_cfg32->val_region,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __to_user_mem_col_cfg(
struct mdp_pa_mem_col_cfg32 __user *mem_col_cfg32,
struct mdp_pa_mem_col_cfg __user *mem_col_cfg)
{
if (copy_in_user(&mem_col_cfg32->color_adjust_p0,
&mem_col_cfg->color_adjust_p0,
sizeof(uint32_t)) ||
copy_in_user(&mem_col_cfg32->color_adjust_p1,
&mem_col_cfg->color_adjust_p1,
sizeof(uint32_t)) ||
copy_in_user(&mem_col_cfg32->hue_region,
&mem_col_cfg->hue_region,
sizeof(uint32_t)) ||
copy_in_user(&mem_col_cfg32->sat_region,
&mem_col_cfg->sat_region,
sizeof(uint32_t)) ||
copy_in_user(&mem_col_cfg32->val_region,
&mem_col_cfg->val_region,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_pa_v2_data(
struct mdp_pa_v2_data32 __user *pa_v2_data32,
struct mdp_pa_v2_data __user *pa_v2_data)
{
uint32_t data;
if (copy_in_user(&pa_v2_data->flags,
&pa_v2_data32->flags,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data->global_hue_adj,
&pa_v2_data32->global_hue_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data->global_sat_adj,
&pa_v2_data32->global_sat_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data->global_val_adj,
&pa_v2_data32->global_val_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data->global_cont_adj,
&pa_v2_data32->global_cont_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data->six_zone_thresh,
&pa_v2_data32->six_zone_thresh,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data->six_zone_len,
&pa_v2_data32->six_zone_len,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, &pa_v2_data32->six_zone_curve_p0) ||
put_user(compat_ptr(data), &pa_v2_data->six_zone_curve_p0) ||
get_user(data, &pa_v2_data32->six_zone_curve_p1) ||
put_user(compat_ptr(data), &pa_v2_data->six_zone_curve_p1))
return -EFAULT;
if (__from_user_mem_col_cfg(
compat_ptr((uintptr_t)&pa_v2_data32->skin_cfg),
&pa_v2_data->skin_cfg) ||
__from_user_mem_col_cfg(
compat_ptr((uintptr_t)&pa_v2_data32->sky_cfg),
&pa_v2_data->sky_cfg) ||
__from_user_mem_col_cfg(
compat_ptr((uintptr_t)&pa_v2_data32->fol_cfg),
&pa_v2_data->fol_cfg))
return -EFAULT;
return 0;
}
static int __to_user_pa_v2_data(
struct mdp_pa_v2_data32 __user *pa_v2_data32,
struct mdp_pa_v2_data __user *pa_v2_data)
{
unsigned long data;
if (copy_in_user(&pa_v2_data32->flags,
&pa_v2_data->flags,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data32->global_hue_adj,
&pa_v2_data->global_hue_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data32->global_sat_adj,
&pa_v2_data->global_sat_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data32->global_val_adj,
&pa_v2_data->global_val_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data32->global_cont_adj,
&pa_v2_data->global_cont_adj,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data32->six_zone_thresh,
&pa_v2_data->six_zone_thresh,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_data32->six_zone_len,
&pa_v2_data->six_zone_len,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, (unsigned long *) &pa_v2_data->six_zone_curve_p0) ||
put_user((compat_caddr_t) data, &pa_v2_data32->six_zone_curve_p0) ||
get_user(data, (unsigned long *) &pa_v2_data->six_zone_curve_p1) ||
put_user((compat_caddr_t) data, &pa_v2_data32->six_zone_curve_p1))
return -EFAULT;
if (__to_user_mem_col_cfg(
compat_ptr((uintptr_t)&pa_v2_data32->skin_cfg),
&pa_v2_data->skin_cfg) ||
__to_user_mem_col_cfg(
compat_ptr((uintptr_t)&pa_v2_data32->sky_cfg),
&pa_v2_data->sky_cfg) ||
__to_user_mem_col_cfg(
compat_ptr((uintptr_t)&pa_v2_data32->fol_cfg),
&pa_v2_data->fol_cfg))
return -EFAULT;
return 0;
}
static inline void __from_user_pa_mem_col_data_v1_7(
struct mdp_pa_mem_col_data_v1_7_32 *mem_col_data32,
struct mdp_pa_mem_col_data_v1_7 *mem_col_data)
{
mem_col_data->color_adjust_p0 = mem_col_data32->color_adjust_p0;
mem_col_data->color_adjust_p1 = mem_col_data32->color_adjust_p1;
mem_col_data->color_adjust_p2 = mem_col_data32->color_adjust_p2;
mem_col_data->blend_gain = mem_col_data32->blend_gain;
mem_col_data->sat_hold = mem_col_data32->sat_hold;
mem_col_data->val_hold = mem_col_data32->val_hold;
mem_col_data->hue_region = mem_col_data32->hue_region;
mem_col_data->sat_region = mem_col_data32->sat_region;
mem_col_data->val_region = mem_col_data32->val_region;
}
static int __from_user_pa_data_v1_7(
struct mdp_pa_v2_cfg_data32 __user *pa_v2_cfg32,
struct mdp_pa_v2_cfg_data __user *pa_v2_cfg)
{
struct mdp_pa_data_v1_7_32 pa_cfg_payload32;
struct mdp_pa_data_v1_7 pa_cfg_payload;
if (copy_from_user(&pa_cfg_payload32,
compat_ptr(pa_v2_cfg32->cfg_payload),
sizeof(pa_cfg_payload32))) {
pr_err("failed to copy the PA payload from userspace\n");
return -EFAULT;
}
memset(&pa_cfg_payload, 0, sizeof(pa_cfg_payload));
pa_cfg_payload.mode = pa_cfg_payload32.mode;
pa_cfg_payload.global_hue_adj = pa_cfg_payload32.global_hue_adj;
pa_cfg_payload.global_sat_adj = pa_cfg_payload32.global_sat_adj;
pa_cfg_payload.global_val_adj = pa_cfg_payload32.global_val_adj;
pa_cfg_payload.global_cont_adj = pa_cfg_payload32.global_cont_adj;
__from_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.skin_cfg,
&pa_cfg_payload.skin_cfg);
__from_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.sky_cfg,
&pa_cfg_payload.sky_cfg);
__from_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.fol_cfg,
&pa_cfg_payload.fol_cfg);
pa_cfg_payload.six_zone_thresh = pa_cfg_payload32.six_zone_thresh;
pa_cfg_payload.six_zone_adj_p0 = pa_cfg_payload32.six_zone_adj_p0;
pa_cfg_payload.six_zone_adj_p1 = pa_cfg_payload32.six_zone_adj_p1;
pa_cfg_payload.six_zone_sat_hold = pa_cfg_payload32.six_zone_sat_hold;
pa_cfg_payload.six_zone_val_hold = pa_cfg_payload32.six_zone_val_hold;
pa_cfg_payload.six_zone_len = pa_cfg_payload32.six_zone_len;
pa_cfg_payload.six_zone_curve_p0 =
compat_ptr(pa_cfg_payload32.six_zone_curve_p0);
pa_cfg_payload.six_zone_curve_p1 =
compat_ptr(pa_cfg_payload32.six_zone_curve_p1);
if (copy_to_user(pa_v2_cfg->cfg_payload, &pa_cfg_payload,
sizeof(pa_cfg_payload))) {
pr_err("Failed to copy to user pa cfg payload\n");
return -EFAULT;
}
return 0;
}
static int __from_user_pa_v2_cfg_data(
struct mdp_pa_v2_cfg_data32 __user *pa_v2_cfg32,
struct mdp_pa_v2_cfg_data __user *pa_v2_cfg)
{
uint32_t version;
if (copy_in_user(&pa_v2_cfg->block,
&pa_v2_cfg32->block,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_cfg->version,
&pa_v2_cfg32->version,
sizeof(uint32_t)) ||
copy_in_user(&pa_v2_cfg->flags,
&pa_v2_cfg32->flags,
sizeof(uint32_t)))
return -EFAULT;
if (copy_from_user(&version,
&pa_v2_cfg32->version,
sizeof(uint32_t))) {
pr_err("failed to copy the version info\n");
return -EFAULT;
}
switch (version) {
case mdp_pa_v1_7:
if (__from_user_pa_data_v1_7(pa_v2_cfg32, pa_v2_cfg)) {
pr_err("failed to get pa data for version %d\n",
version);
return -EFAULT;
}
break;
default:
pr_debug("version invalid, fallback to legacy\n");
if (__from_user_pa_v2_data(
compat_ptr((uintptr_t)&pa_v2_cfg32->pa_v2_data),
&pa_v2_cfg->pa_v2_data))
return -EFAULT;
break;
}
return 0;
}
static inline void __to_user_pa_mem_col_data_v1_7(
struct mdp_pa_mem_col_data_v1_7_32 *mem_col_data32,
struct mdp_pa_mem_col_data_v1_7 *mem_col_data)
{
mem_col_data32->color_adjust_p0 = mem_col_data->color_adjust_p0;
mem_col_data32->color_adjust_p1 = mem_col_data->color_adjust_p1;
mem_col_data32->color_adjust_p2 = mem_col_data->color_adjust_p2;
mem_col_data32->blend_gain = mem_col_data->blend_gain;
mem_col_data32->sat_hold = mem_col_data->sat_hold;
mem_col_data32->val_hold = mem_col_data->val_hold;
mem_col_data32->hue_region = mem_col_data->hue_region;
mem_col_data32->sat_region = mem_col_data->sat_region;
mem_col_data32->val_region = mem_col_data->val_region;
}
static int __to_user_pa_data_v1_7(
struct mdp_pa_v2_cfg_data32 __user *pa_v2_cfg32,
struct mdp_pa_v2_cfg_data __user *pa_v2_cfg)
{
struct mdp_pa_data_v1_7_32 pa_cfg_payload32;
struct mdp_pa_data_v1_7 pa_cfg_payload;
if (copy_from_user(&pa_cfg_payload,
pa_v2_cfg->cfg_payload,
sizeof(pa_cfg_payload))) {
pr_err("failed to copy the PA payload from userspace\n");
return -EFAULT;
}
pa_cfg_payload32.mode = pa_cfg_payload.mode;
pa_cfg_payload32.global_hue_adj = pa_cfg_payload.global_hue_adj;
pa_cfg_payload32.global_sat_adj = pa_cfg_payload.global_sat_adj;
pa_cfg_payload32.global_val_adj = pa_cfg_payload.global_val_adj;
pa_cfg_payload32.global_cont_adj = pa_cfg_payload.global_cont_adj;
__to_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.skin_cfg,
&pa_cfg_payload.skin_cfg);
__to_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.sky_cfg,
&pa_cfg_payload.sky_cfg);
__to_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.fol_cfg,
&pa_cfg_payload.fol_cfg);
pa_cfg_payload32.six_zone_thresh = pa_cfg_payload.six_zone_thresh;
pa_cfg_payload32.six_zone_adj_p0 = pa_cfg_payload.six_zone_adj_p0;
pa_cfg_payload32.six_zone_adj_p1 = pa_cfg_payload.six_zone_adj_p1;
pa_cfg_payload32.six_zone_sat_hold = pa_cfg_payload.six_zone_sat_hold;
pa_cfg_payload32.six_zone_val_hold = pa_cfg_payload.six_zone_val_hold;
pa_cfg_payload32.six_zone_len = pa_cfg_payload.six_zone_len;
if (copy_to_user(compat_ptr(pa_v2_cfg32->cfg_payload),
&pa_cfg_payload32,
sizeof(pa_cfg_payload32))) {
pr_err("Failed to copy to user pa cfg payload\n");
return -EFAULT;
}
return 0;
}
static int __to_user_pa_v2_cfg_data(
struct mdp_pa_v2_cfg_data32 __user *pa_v2_cfg32,
struct mdp_pa_v2_cfg_data __user *pa_v2_cfg)
{
uint32_t version = 0;
uint32_t flags = 0;
if (copy_from_user(&version,
&pa_v2_cfg32->version,
sizeof(uint32_t)))
return -EFAULT;
switch (version) {
case mdp_pa_v1_7:
if (copy_from_user(&flags,
&pa_v2_cfg32->flags,
sizeof(uint32_t))) {
pr_err("failed to get PA v1_7 flags\n");
return -EFAULT;
}
if (!(flags & MDP_PP_OPS_READ)) {
pr_debug("Read op not set. Skipping compat copyback\n");
return 0;
}
if (__to_user_pa_data_v1_7(pa_v2_cfg32, pa_v2_cfg)) {
pr_err("failed to set pa data for version %d\n",
version);
return -EFAULT;
}
break;
default:
pr_debug("version invalid, fallback to legacy\n");
if (copy_from_user(&flags,
&pa_v2_cfg32->pa_v2_data.flags,
sizeof(uint32_t))) {
pr_err("failed to get PAv2 flags\n");
return -EFAULT;
}
if (!(flags & MDP_PP_OPS_READ)) {
pr_debug("Read op not set. Skipping compat copyback\n");
return 0;
}
if (__to_user_pa_v2_data(
compat_ptr((uintptr_t)&pa_v2_cfg32->pa_v2_data),
&pa_v2_cfg->pa_v2_data))
return -EFAULT;
break;
}
return 0;
}
static int __from_user_dither_cfg_data(
struct mdp_dither_cfg_data32 __user *dither_cfg32,
struct mdp_dither_cfg_data __user *dither_cfg)
{
if (copy_in_user(&dither_cfg->block,
&dither_cfg32->block,
sizeof(uint32_t)) ||
copy_in_user(&dither_cfg->flags,
&dither_cfg32->flags,
sizeof(uint32_t)) ||
copy_in_user(&dither_cfg->g_y_depth,
&dither_cfg32->g_y_depth,
sizeof(uint32_t)) ||
copy_in_user(&dither_cfg->r_cr_depth,
&dither_cfg32->r_cr_depth,
sizeof(uint32_t)) ||
copy_in_user(&dither_cfg->b_cb_depth,
&dither_cfg32->b_cb_depth,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __to_user_dither_cfg_data(
struct mdp_dither_cfg_data32 __user *dither_cfg32,
struct mdp_dither_cfg_data __user *dither_cfg)
{
if (copy_in_user(&dither_cfg32->block,
&dither_cfg->block,
sizeof(uint32_t)) ||
copy_in_user(&dither_cfg32->flags,
&dither_cfg->flags,
sizeof(uint32_t)) ||
copy_in_user(&dither_cfg32->g_y_depth,
&dither_cfg->g_y_depth,
sizeof(uint32_t)) ||
copy_in_user(&dither_cfg32->r_cr_depth,
&dither_cfg->r_cr_depth,
sizeof(uint32_t)) ||
copy_in_user(&dither_cfg32->b_cb_depth,
&dither_cfg->b_cb_depth,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_gamut_cfg_data_v17(
struct mdp_gamut_cfg_data32 __user *gamut_cfg32,
struct mdp_gamut_cfg_data __user *gamut_cfg)
{
struct mdp_gamut_data_v1_7 gamut_cfg_payload;
struct mdp_gamut_data_v1_7_32 gamut_cfg_payload32;
u32 i = 0;
if (copy_from_user(&gamut_cfg_payload32,
compat_ptr(gamut_cfg32->cfg_payload),
sizeof(gamut_cfg_payload32))) {
pr_err("failed to copy the gamut payload from userspace\n");
return -EFAULT;
}
memset(&gamut_cfg_payload, 0, sizeof(gamut_cfg_payload));
gamut_cfg_payload.mode = gamut_cfg_payload32.mode;
for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
gamut_cfg_payload.tbl_size[i] =
gamut_cfg_payload32.tbl_size[i];
gamut_cfg_payload.c0_data[i] =
compat_ptr(gamut_cfg_payload32.c0_data[i]);
gamut_cfg_payload.c1_c2_data[i] =
compat_ptr(gamut_cfg_payload32.c1_c2_data[i]);
}
for (i = 0; i < MDP_GAMUT_SCALE_OFF_TABLE_NUM; i++) {
gamut_cfg_payload.tbl_scale_off_sz[i] =
gamut_cfg_payload32.tbl_scale_off_sz[i];
gamut_cfg_payload.scale_off_data[i] =
compat_ptr(gamut_cfg_payload32.scale_off_data[i]);
}
if (copy_to_user(gamut_cfg->cfg_payload, &gamut_cfg_payload,
sizeof(gamut_cfg_payload))) {
pr_err("failed to copy the gamut payload to userspace\n");
return -EFAULT;
}
return 0;
}
static int __from_user_gamut_cfg_data(
struct mdp_gamut_cfg_data32 __user *gamut_cfg32,
struct mdp_gamut_cfg_data __user *gamut_cfg)
{
uint32_t data, version;
int i;
if (copy_in_user(&gamut_cfg->block,
&gamut_cfg32->block,
sizeof(uint32_t)) ||
copy_in_user(&gamut_cfg->flags,
&gamut_cfg32->flags,
sizeof(uint32_t)) ||
copy_in_user(&gamut_cfg->gamut_first,
&gamut_cfg32->gamut_first,
sizeof(uint32_t)) ||
copy_in_user(&gamut_cfg->tbl_size[0],
&gamut_cfg32->tbl_size[0],
MDP_GAMUT_TABLE_NUM * sizeof(uint32_t)) ||
copy_in_user(&gamut_cfg->version,
&gamut_cfg32->version,
sizeof(uint32_t)))
return 0;
if (copy_from_user(&version, &gamut_cfg32->version, sizeof(u32))) {
pr_err("failed to copy the version info\n");
return -EFAULT;
}
switch (version) {
case mdp_gamut_v1_7:
if (__from_user_gamut_cfg_data_v17(gamut_cfg32, gamut_cfg)) {
pr_err("failed to get the gamut data for version %d\n",
version);
return -EFAULT;
}
break;
default:
pr_debug("version invalid fallback to legacy\n");
/* The Gamut LUT data contains 3 static arrays for R, G, and B
* gamut data. Each these arrays contains pointers dynamic arrays
* which hold the gamut LUTs for R, G, and B. Must copy the array of
* pointers from 32 bit to 64 bit addresses. */
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
if (get_user(data, &gamut_cfg32->r_tbl[i]) ||
put_user(compat_ptr(data), &gamut_cfg->r_tbl[i]))
return -EFAULT;
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
if (get_user(data, &gamut_cfg32->g_tbl[i]) ||
put_user(compat_ptr(data), &gamut_cfg->g_tbl[i]))
return -EFAULT;
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
if (get_user(data, &gamut_cfg32->b_tbl[i]) ||
put_user(compat_ptr(data), &gamut_cfg->b_tbl[i]))
return -EFAULT;
}
break;
}
return 0;
}
static int __to_user_gamut_cfg_data(
struct mdp_gamut_cfg_data32 __user *gamut_cfg32,
struct mdp_gamut_cfg_data __user *gamut_cfg)
{
unsigned long data;
int i;
if (copy_in_user(&gamut_cfg32->block,
&gamut_cfg->block,
sizeof(uint32_t)) ||
copy_in_user(&gamut_cfg32->flags,
&gamut_cfg->flags,
sizeof(uint32_t)) ||
copy_in_user(&gamut_cfg32->gamut_first,
&gamut_cfg->gamut_first,
sizeof(uint32_t)) ||
copy_in_user(&gamut_cfg32->tbl_size[0],
&gamut_cfg->tbl_size[0],
MDP_GAMUT_TABLE_NUM * sizeof(uint32_t)))
return 0;
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
if (get_user(data, (unsigned long *) &gamut_cfg->r_tbl[i]) ||
put_user((compat_caddr_t)data, &gamut_cfg32->r_tbl[i]))
return -EFAULT;
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
if (get_user(data, (unsigned long *) &gamut_cfg->g_tbl[i]) ||
put_user((compat_caddr_t)data, &gamut_cfg32->g_tbl[i]))
return -EFAULT;
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
if (get_user(data, (unsigned long *) &gamut_cfg->b_tbl[i]) ||
put_user((compat_caddr_t)data, &gamut_cfg32->g_tbl[i]))
return -EFAULT;
}
return 0;
}
static int __from_user_calib_config_data(
struct mdp_calib_config_data32 __user *calib_cfg32,
struct mdp_calib_config_data __user *calib_cfg)
{
if (copy_in_user(&calib_cfg->ops,
&calib_cfg32->ops,
sizeof(uint32_t)) ||
copy_in_user(&calib_cfg->addr,
&calib_cfg32->addr,
sizeof(uint32_t)) ||
copy_in_user(&calib_cfg->data,
&calib_cfg32->data,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __to_user_calib_config_data(
struct mdp_calib_config_data32 __user *calib_cfg32,
struct mdp_calib_config_data __user *calib_cfg)
{
if (copy_in_user(&calib_cfg32->ops,
&calib_cfg->ops,
sizeof(uint32_t)) ||
copy_in_user(&calib_cfg32->addr,
&calib_cfg->addr,
sizeof(uint32_t)) ||
copy_in_user(&calib_cfg32->data,
&calib_cfg->data,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_ad_init(
struct mdss_ad_init32 __user *ad_init32,
struct mdss_ad_init __user *ad_init)
{
uint32_t data;
if (copy_in_user(&ad_init->asym_lut[0],
&ad_init32->asym_lut[0],
33 * sizeof(uint32_t)) ||
copy_in_user(&ad_init->color_corr_lut[0],
&ad_init32->color_corr_lut[0],
33 * sizeof(uint32_t)) ||
copy_in_user(&ad_init->i_control[0],
&ad_init32->i_control[0],
2 * sizeof(uint8_t)) ||
copy_in_user(&ad_init->black_lvl,
&ad_init32->black_lvl,
sizeof(uint16_t)) ||
copy_in_user(&ad_init->white_lvl,
&ad_init32->white_lvl,
sizeof(uint16_t)) ||
copy_in_user(&ad_init->var,
&ad_init32->var,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->limit_ampl,
&ad_init32->limit_ampl,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->i_dither,
&ad_init32->i_dither,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->slope_max,
&ad_init32->slope_max,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->slope_min,
&ad_init32->slope_min,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->dither_ctl,
&ad_init32->dither_ctl,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->format,
&ad_init32->format,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->auto_size,
&ad_init32->auto_size,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->frame_w,
&ad_init32->frame_w,
sizeof(uint16_t)) ||
copy_in_user(&ad_init->frame_h,
&ad_init32->frame_h,
sizeof(uint16_t)) ||
copy_in_user(&ad_init->logo_v,
&ad_init32->logo_v,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->logo_h,
&ad_init32->logo_h,
sizeof(uint8_t)) ||
copy_in_user(&ad_init->alpha,
&ad_init32->alpha,
sizeof(uint32_t)) ||
copy_in_user(&ad_init->alpha_base,
&ad_init32->alpha_base,
sizeof(uint32_t)) ||
copy_in_user(&ad_init->bl_lin_len,
&ad_init32->bl_lin_len,
sizeof(uint32_t)) ||
copy_in_user(&ad_init->bl_att_len,
&ad_init32->bl_att_len,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, &ad_init32->bl_lin) ||
put_user(compat_ptr(data), &ad_init->bl_lin) ||
get_user(data, &ad_init32->bl_lin_inv) ||
put_user(compat_ptr(data), &ad_init->bl_lin_inv) ||
get_user(data, &ad_init32->bl_att_lut) ||
put_user(compat_ptr(data), &ad_init->bl_att_lut))
return -EFAULT;
return 0;
}
static int __from_user_ad_cfg(
struct mdss_ad_cfg32 __user *ad_cfg32,
struct mdss_ad_cfg __user *ad_cfg)
{
if (copy_in_user(&ad_cfg->mode,
&ad_cfg32->mode,
sizeof(uint32_t)) ||
copy_in_user(&ad_cfg->al_calib_lut[0],
&ad_cfg32->al_calib_lut[0],
33 * sizeof(uint32_t)) ||
copy_in_user(&ad_cfg->backlight_min,
&ad_cfg32->backlight_min,
sizeof(uint16_t)) ||
copy_in_user(&ad_cfg->backlight_max,
&ad_cfg32->backlight_max,
sizeof(uint16_t)) ||
copy_in_user(&ad_cfg->backlight_scale,
&ad_cfg32->backlight_scale,
sizeof(uint16_t)) ||
copy_in_user(&ad_cfg->amb_light_min,
&ad_cfg32->amb_light_min,
sizeof(uint16_t)) ||
copy_in_user(&ad_cfg->filter[0],
&ad_cfg32->filter[0],
2 * sizeof(uint16_t)) ||
copy_in_user(&ad_cfg->calib[0],
&ad_cfg32->calib[0],
4 * sizeof(uint16_t)) ||
copy_in_user(&ad_cfg->strength_limit,
&ad_cfg32->strength_limit,
sizeof(uint8_t)) ||
copy_in_user(&ad_cfg->t_filter_recursion,
&ad_cfg32->t_filter_recursion,
sizeof(uint8_t)) ||
copy_in_user(&ad_cfg->stab_itr,
&ad_cfg32->stab_itr,
sizeof(uint16_t)) ||
copy_in_user(&ad_cfg->bl_ctrl_mode,
&ad_cfg32->bl_ctrl_mode,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_ad_init_cfg(
struct mdss_ad_init_cfg32 __user *ad_info32,
struct mdss_ad_init_cfg __user *ad_info)
{
uint32_t op;
if (copy_from_user(&op, &ad_info32->ops,
sizeof(uint32_t)))
return -EFAULT;
if (copy_in_user(&ad_info->ops,
&ad_info32->ops,
sizeof(uint32_t)))
return -EFAULT;
if (op & MDP_PP_AD_INIT) {
if (__from_user_ad_init(
compat_ptr((uintptr_t)&ad_info32->params.init),
&ad_info->params.init))
return -EFAULT;
} else if (op & MDP_PP_AD_CFG) {
if (__from_user_ad_cfg(
compat_ptr((uintptr_t)&ad_info32->params.cfg),
&ad_info->params.cfg))
return -EFAULT;
} else {
pr_err("Invalid AD init/config operation\n");
return -EINVAL;
}
return 0;
}
static int __from_user_ad_input(
struct mdss_ad_input32 __user *ad_input32,
struct mdss_ad_input __user *ad_input)
{
int mode;
if (copy_from_user(&mode,
&ad_input32->mode,
sizeof(uint32_t)))
return -EFAULT;
if (copy_in_user(&ad_input->mode,
&ad_input32->mode,
sizeof(uint32_t)) ||
copy_in_user(&ad_input->output,
&ad_input32->output,
sizeof(uint32_t)))
return -EFAULT;
switch (mode) {
case MDSS_AD_MODE_AUTO_BL:
case MDSS_AD_MODE_AUTO_STR:
if (copy_in_user(&ad_input->in.amb_light,
&ad_input32->in.amb_light,
sizeof(uint32_t)))
return -EFAULT;
break;
case MDSS_AD_MODE_TARG_STR:
case MDSS_AD_MODE_MAN_STR:
if (copy_in_user(&ad_input->in.strength,
&ad_input32->in.strength,
sizeof(uint32_t)))
return -EFAULT;
break;
case MDSS_AD_MODE_CALIB:
if (copy_in_user(&ad_input->in.calib_bl,
&ad_input32->in.calib_bl,
sizeof(uint32_t)))
return -EFAULT;
break;
}
return 0;
}
static int __to_user_ad_input(
struct mdss_ad_input32 __user *ad_input32,
struct mdss_ad_input __user *ad_input)
{
int mode;
if (copy_from_user(&mode,
&ad_input->mode,
sizeof(uint32_t)))
return -EFAULT;
if (copy_in_user(&ad_input32->mode,
&ad_input->mode,
sizeof(uint32_t)) ||
copy_in_user(&ad_input32->output,
&ad_input->output,
sizeof(uint32_t)))
return -EFAULT;
switch (mode) {
case MDSS_AD_MODE_AUTO_BL:
case MDSS_AD_MODE_AUTO_STR:
if (copy_in_user(&ad_input32->in.amb_light,
&ad_input->in.amb_light,
sizeof(uint32_t)))
return -EFAULT;
break;
case MDSS_AD_MODE_TARG_STR:
case MDSS_AD_MODE_MAN_STR:
if (copy_in_user(&ad_input32->in.strength,
&ad_input->in.strength,
sizeof(uint32_t)))
return -EFAULT;
break;
case MDSS_AD_MODE_CALIB:
if (copy_in_user(&ad_input32->in.calib_bl,
&ad_input->in.calib_bl,
sizeof(uint32_t)))
return -EFAULT;
break;
}
return 0;
}
static int __from_user_calib_cfg(
struct mdss_calib_cfg32 __user *calib_cfg32,
struct mdss_calib_cfg __user *calib_cfg)
{
if (copy_in_user(&calib_cfg->ops,
&calib_cfg32->ops,
sizeof(uint32_t)) ||
copy_in_user(&calib_cfg->calib_mask,
&calib_cfg32->calib_mask,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static int __from_user_calib_config_buffer(
struct mdp_calib_config_buffer32 __user *calib_buffer32,
struct mdp_calib_config_buffer __user *calib_buffer)
{
uint32_t data;
if (copy_in_user(&calib_buffer->ops,
&calib_buffer32->ops,
sizeof(uint32_t)) ||
copy_in_user(&calib_buffer->size,
&calib_buffer32->size,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, &calib_buffer32->buffer) ||
put_user(compat_ptr(data), &calib_buffer->buffer))
return -EFAULT;
return 0;
}
static int __to_user_calib_config_buffer(
struct mdp_calib_config_buffer32 __user *calib_buffer32,
struct mdp_calib_config_buffer __user *calib_buffer)
{
unsigned long data;
if (copy_in_user(&calib_buffer32->ops,
&calib_buffer->ops,
sizeof(uint32_t)) ||
copy_in_user(&calib_buffer32->size,
&calib_buffer->size,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, (unsigned long *) &calib_buffer->buffer) ||
put_user((compat_caddr_t) data, &calib_buffer32->buffer))
return -EFAULT;
return 0;
}
static int __from_user_calib_dcm_state(
struct mdp_calib_dcm_state32 __user *calib_dcm32,
struct mdp_calib_dcm_state __user *calib_dcm)
{
if (copy_in_user(&calib_dcm->ops,
&calib_dcm32->ops,
sizeof(uint32_t)) ||
copy_in_user(&calib_dcm->dcm_state,
&calib_dcm32->dcm_state,
sizeof(uint32_t)))
return -EFAULT;
return 0;
}
static u32 __pp_compat_size_igc(void)
{
u32 alloc_size = 0;
/* When we have mutiple versions pick largest struct size */
alloc_size = sizeof(struct mdp_igc_lut_data_v1_7);
return alloc_size;
}
static u32 __pp_compat_size_hist_lut(void)
{
u32 alloc_size = 0;
/* When we have mutiple versions pick largest struct size */
alloc_size = sizeof(struct mdp_hist_lut_data_v1_7);
return alloc_size;
}
static u32 __pp_compat_size_pgc(void)
{
u32 tbl_sz_max = 0;
tbl_sz_max = 3 * GC_LUT_SEGMENTS * sizeof(struct mdp_ar_gc_lut_data);
tbl_sz_max += sizeof(struct mdp_pgc_lut_data_v1_7);
return tbl_sz_max;
}
static u32 __pp_compat_size_pcc(void)
{
/* if new version of PCC is added return max struct size */
return sizeof(struct mdp_pcc_data_v1_7);
}
static u32 __pp_compat_size_pa(void)
{
/* if new version of PA is added return max struct size */
return sizeof(struct mdp_pa_data_v1_7);
}
static u32 __pp_compat_size_gamut(void)
{
return sizeof(struct mdp_gamut_data_v1_7);
}
static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32,
struct msmfb_mdp_pp __user **pp,
uint32_t op)
{
uint32_t alloc_size = 0, lut_type, pgc_size = 0;
alloc_size = sizeof(struct msmfb_mdp_pp);
switch (op) {
case mdp_op_lut_cfg:
if (copy_from_user(&lut_type,
&pp32->data.lut_cfg_data.lut_type,
sizeof(uint32_t)))
return -EFAULT;
switch (lut_type) {
case mdp_lut_pgc:
pgc_size = GC_LUT_SEGMENTS *
sizeof(struct mdp_ar_gc_lut_data);
alloc_size += __pp_compat_size_pgc();
*pp = compat_alloc_user_space(alloc_size);
if (NULL == *pp)
return -ENOMEM;
memset(*pp, 0, alloc_size);
(*pp)->data.lut_cfg_data.data.pgc_lut_data.r_data =
(struct mdp_ar_gc_lut_data *)
((unsigned long) *pp +
sizeof(struct msmfb_mdp_pp));
(*pp)->data.lut_cfg_data.data.pgc_lut_data.g_data =
(struct mdp_ar_gc_lut_data *)
((unsigned long) *pp +
sizeof(struct msmfb_mdp_pp) +
pgc_size);
(*pp)->data.lut_cfg_data.data.pgc_lut_data.b_data =
(struct mdp_ar_gc_lut_data *)
((unsigned long) *pp +
sizeof(struct msmfb_mdp_pp) +
(2 * pgc_size));
(*pp)->data.lut_cfg_data.data.pgc_lut_data.cfg_payload
= (void *)((unsigned long) *pp +
sizeof(struct msmfb_mdp_pp) +
(3 * pgc_size));
break;
case mdp_lut_igc:
alloc_size += __pp_compat_size_igc();
*pp = compat_alloc_user_space(alloc_size);
if (NULL == *pp) {
pr_err("failed to alloc from user size %d for igc\n",
alloc_size);
return -ENOMEM;
}
memset(*pp, 0, alloc_size);
(*pp)->data.lut_cfg_data.data.igc_lut_data.cfg_payload
= (void *)((unsigned long)(*pp) +
sizeof(struct msmfb_mdp_pp));
break;
case mdp_lut_hist:
alloc_size += __pp_compat_size_hist_lut();
*pp = compat_alloc_user_space(alloc_size);
if (NULL == *pp) {
pr_err("failed to alloc from user size %d for hist lut\n",
alloc_size);
return -ENOMEM;
}
memset(*pp, 0, alloc_size);
(*pp)->data.lut_cfg_data.data.hist_lut_data.cfg_payload
= (void *)((unsigned long)(*pp) +
sizeof(struct msmfb_mdp_pp));
break;
default:
*pp = compat_alloc_user_space(alloc_size);
if (NULL == *pp) {
pr_err("failed to alloc from user size %d for lut_type %d\n",
alloc_size, lut_type);
return -ENOMEM;
}
memset(*pp, 0, alloc_size);
break;
}
break;
case mdp_op_pcc_cfg:
alloc_size += __pp_compat_size_pcc();
*pp = compat_alloc_user_space(alloc_size);
if (NULL == *pp) {
pr_err("alloc from user size %d for pcc fail\n",
alloc_size);
return -ENOMEM;
}
memset(*pp, 0, alloc_size);
(*pp)->data.pcc_cfg_data.cfg_payload =
(void *)((unsigned long)(*pp) +
sizeof(struct msmfb_mdp_pp));
break;
case mdp_op_gamut_cfg:
alloc_size += __pp_compat_size_gamut();
*pp = compat_alloc_user_space(alloc_size);
if (NULL == *pp) {
pr_err("alloc from user size %d for pcc fail\n",
alloc_size);
return -ENOMEM;
}
memset(*pp, 0, alloc_size);
(*pp)->data.gamut_cfg_data.cfg_payload =
(void *)((unsigned long)(*pp) +
sizeof(struct msmfb_mdp_pp));
break;
case mdp_op_pa_v2_cfg:
alloc_size += __pp_compat_size_pa();
*pp = compat_alloc_user_space(alloc_size);
if (NULL == *pp) {
pr_err("alloc from user size %d for pcc fail\n",
alloc_size);
return -ENOMEM;
}
memset(*pp, 0, alloc_size);
(*pp)->data.pa_v2_cfg_data.cfg_payload =
(void *)((unsigned long)(*pp) +
sizeof(struct msmfb_mdp_pp));
break;
default:
*pp = compat_alloc_user_space(alloc_size);
if (NULL == *pp)
return -ENOMEM;
memset(*pp, 0, alloc_size);
break;
}
return 0;
}
static int mdss_compat_pp_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg, struct file *file)
{
uint32_t op;
int ret = 0;
struct msmfb_mdp_pp32 __user *pp32;
struct msmfb_mdp_pp __user *pp;
pp32 = compat_ptr(arg);
if (copy_from_user(&op, &pp32->op, sizeof(uint32_t)))
return -EFAULT;
ret = __pp_compat_alloc(pp32, &pp, op);
if (ret)
return ret;
if (copy_in_user(&pp->op, &pp32->op, sizeof(uint32_t)))
return -EFAULT;
switch (op) {
case mdp_op_pcc_cfg:
ret = __from_user_pcc_cfg_data(
compat_ptr((uintptr_t)&pp32->data.pcc_cfg_data),
&pp->data.pcc_cfg_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_pcc_cfg_data(
compat_ptr((uintptr_t)&pp32->data.pcc_cfg_data),
&pp->data.pcc_cfg_data);
break;
case mdp_op_csc_cfg:
ret = __from_user_csc_cfg_data(
compat_ptr((uintptr_t)&pp32->data.csc_cfg_data),
&pp->data.csc_cfg_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_csc_cfg_data(
compat_ptr((uintptr_t)&pp32->data.csc_cfg_data),
&pp->data.csc_cfg_data);
break;
case mdp_op_lut_cfg:
ret = __from_user_lut_cfg_data(
compat_ptr((uintptr_t)&pp32->data.lut_cfg_data),
&pp->data.lut_cfg_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_lut_cfg_data(
compat_ptr((uintptr_t)&pp32->data.lut_cfg_data),
&pp->data.lut_cfg_data);
break;
case mdp_op_qseed_cfg:
ret = __from_user_qseed_cfg_data(
compat_ptr((uintptr_t)&pp32->data.qseed_cfg_data),
&pp->data.qseed_cfg_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_qseed_cfg_data(
compat_ptr((uintptr_t)&pp32->data.qseed_cfg_data),
&pp->data.qseed_cfg_data);
break;
case mdp_bl_scale_cfg:
ret = __from_user_bl_scale_data(
compat_ptr((uintptr_t)&pp32->data.bl_scale_data),
&pp->data.bl_scale_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
break;
case mdp_op_pa_cfg:
ret = __from_user_pa_cfg_data(
compat_ptr((uintptr_t)&pp32->data.pa_cfg_data),
&pp->data.pa_cfg_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_pa_cfg_data(
compat_ptr((uintptr_t)&pp32->data.pa_cfg_data),
&pp->data.pa_cfg_data);
break;
case mdp_op_pa_v2_cfg:
ret = __from_user_pa_v2_cfg_data(
compat_ptr((uintptr_t)&pp32->data.pa_v2_cfg_data),
&pp->data.pa_v2_cfg_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_pa_v2_cfg_data(
compat_ptr((uintptr_t)&pp32->data.pa_v2_cfg_data),
&pp->data.pa_v2_cfg_data);
break;
case mdp_op_dither_cfg:
ret = __from_user_dither_cfg_data(
compat_ptr((uintptr_t)&pp32->data.dither_cfg_data),
&pp->data.dither_cfg_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_dither_cfg_data(
compat_ptr((uintptr_t)&pp32->data.dither_cfg_data),
&pp->data.dither_cfg_data);
break;
case mdp_op_gamut_cfg:
ret = __from_user_gamut_cfg_data(
compat_ptr((uintptr_t)&pp32->data.gamut_cfg_data),
&pp->data.gamut_cfg_data);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_gamut_cfg_data(
compat_ptr((uintptr_t)&pp32->data.gamut_cfg_data),
&pp->data.gamut_cfg_data);
break;
case mdp_op_calib_cfg:
ret = __from_user_calib_config_data(
compat_ptr((uintptr_t)&pp32->data.calib_cfg),
&pp->data.calib_cfg);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_calib_config_data(
compat_ptr((uintptr_t)&pp32->data.calib_cfg),
&pp->data.calib_cfg);
break;
case mdp_op_ad_cfg:
ret = __from_user_ad_init_cfg(
compat_ptr((uintptr_t)&pp32->data.ad_init_cfg),
&pp->data.ad_init_cfg);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
break;
case mdp_op_ad_input:
ret = __from_user_ad_input(
compat_ptr((uintptr_t)&pp32->data.ad_input),
&pp->data.ad_input);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_ad_input(
compat_ptr((uintptr_t)&pp32->data.ad_input),
&pp->data.ad_input);
break;
case mdp_op_calib_mode:
ret = __from_user_calib_cfg(
compat_ptr((uintptr_t)&pp32->data.mdss_calib_cfg),
&pp->data.mdss_calib_cfg);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
break;
case mdp_op_calib_buffer:
ret = __from_user_calib_config_buffer(
compat_ptr((uintptr_t)&pp32->data.calib_buffer),
&pp->data.calib_buffer);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
if (ret)
goto pp_compat_exit;
ret = __to_user_calib_config_buffer(
compat_ptr((uintptr_t)&pp32->data.calib_buffer),
&pp->data.calib_buffer);
break;
case mdp_op_calib_dcm_state:
ret = __from_user_calib_dcm_state(
compat_ptr((uintptr_t)&pp32->data.calib_dcm),
&pp->data.calib_dcm);
if (ret)
goto pp_compat_exit;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file);
break;
default:
break;
}
pp_compat_exit:
return ret;
}
static int __from_user_pp_params(struct mdp_overlay_pp_params32 *ppp32,
struct mdp_overlay_pp_params *ppp)
{
int ret = 0;
if (copy_in_user(&ppp->config_ops,
&ppp32->config_ops,
sizeof(uint32_t)))
return -EFAULT;
ret = __from_user_csc_cfg(
compat_ptr((uintptr_t)&ppp32->csc_cfg),
&ppp->csc_cfg);
if (ret)
return ret;
ret = __from_user_qseed_cfg(
compat_ptr((uintptr_t)&ppp32->qseed_cfg[0]),
&ppp->qseed_cfg[0]);
if (ret)
return ret;
ret = __from_user_qseed_cfg(
compat_ptr((uintptr_t)&ppp32->qseed_cfg[1]),
&ppp->qseed_cfg[1]);
if (ret)
return ret;
ret = __from_user_pa_cfg(
compat_ptr((uintptr_t)&ppp32->pa_cfg),
&ppp->pa_cfg);
if (ret)
return ret;
ret = __from_user_igc_lut_data(
compat_ptr((uintptr_t)&ppp32->igc_cfg),
&ppp->igc_cfg);
if (ret)
return ret;
ret = __from_user_sharp_cfg(
compat_ptr((uintptr_t)&ppp32->sharp_cfg),
&ppp->sharp_cfg);
if (ret)
return ret;
ret = __from_user_histogram_cfg(
compat_ptr((uintptr_t)&ppp32->hist_cfg),
&ppp->hist_cfg);
if (ret)
return ret;
ret = __from_user_hist_lut_data(
compat_ptr((uintptr_t)&ppp32->hist_lut_cfg),
&ppp->hist_lut_cfg);
if (ret)
return ret;
ret = __from_user_pa_v2_data(
compat_ptr((uintptr_t)&ppp32->pa_v2_cfg),
&ppp->pa_v2_cfg);
return ret;
}
static int __to_user_pp_params(struct mdp_overlay_pp_params *ppp,
struct mdp_overlay_pp_params32 *ppp32)
{
int ret = 0;
if (copy_in_user(&ppp32->config_ops,
&ppp->config_ops,
sizeof(uint32_t)))
return -EFAULT;
ret = __to_user_csc_cfg(
compat_ptr((uintptr_t)&ppp32->csc_cfg),
&ppp->csc_cfg);
if (ret)
return ret;
ret = __to_user_qseed_cfg(
compat_ptr((uintptr_t)&ppp32->qseed_cfg[0]),
&ppp->qseed_cfg[0]);
if (ret)
return ret;
ret = __to_user_qseed_cfg(
compat_ptr((uintptr_t)&ppp32->qseed_cfg[1]),
&ppp->qseed_cfg[1]);
if (ret)
return ret;
ret = __to_user_pa_cfg(
compat_ptr((uintptr_t)&ppp32->pa_cfg),
&ppp->pa_cfg);
if (ret)
return ret;
ret = __to_user_igc_lut_data(
compat_ptr((uintptr_t)&ppp32->igc_cfg),
&ppp->igc_cfg);
if (ret)
return ret;
ret = __to_user_sharp_cfg(
compat_ptr((uintptr_t)&ppp32->sharp_cfg),
&ppp->sharp_cfg);
if (ret)
return ret;
ret = __to_user_histogram_cfg(
compat_ptr((uintptr_t)&ppp32->hist_cfg),
&ppp->hist_cfg);
if (ret)
return ret;
ret = __to_user_hist_lut_data(
compat_ptr((uintptr_t)&ppp32->hist_lut_cfg),
&ppp->hist_lut_cfg);
if (ret)
return ret;
ret = __to_user_pa_v2_data(
compat_ptr((uintptr_t)&ppp32->pa_v2_cfg),
&ppp->pa_v2_cfg);
return ret;
}
static int __from_user_hist_start_req(
struct mdp_histogram_start_req32 __user *hist_req32,
struct mdp_histogram_start_req __user *hist_req)
{
if (copy_in_user(&hist_req->block,
&hist_req32->block,
sizeof(uint32_t)) ||
copy_in_user(&hist_req->frame_cnt,
&hist_req32->frame_cnt,
sizeof(uint8_t)) ||
copy_in_user(&hist_req->bit_mask,
&hist_req32->bit_mask,
sizeof(uint8_t)) ||
copy_in_user(&hist_req->num_bins,
&hist_req32->num_bins,
sizeof(uint16_t)))
return -EFAULT;
return 0;
}
static int __from_user_hist_data(
struct mdp_histogram_data32 __user *hist_data32,
struct mdp_histogram_data __user *hist_data)
{
uint32_t data;
if (copy_in_user(&hist_data->block,
&hist_data32->block,
sizeof(uint32_t)) ||
copy_in_user(&hist_data->bin_cnt,
&hist_data32->bin_cnt,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, &hist_data32->c0) ||
put_user(compat_ptr(data), &hist_data->c0) ||
get_user(data, &hist_data32->c1) ||
put_user(compat_ptr(data), &hist_data->c1) ||
get_user(data, &hist_data32->c2) ||
put_user(compat_ptr(data), &hist_data->c2) ||
get_user(data, &hist_data32->extra_info) ||
put_user(compat_ptr(data), &hist_data->extra_info))
return -EFAULT;
return 0;
}
static int __to_user_hist_data(
struct mdp_histogram_data32 __user *hist_data32,
struct mdp_histogram_data __user *hist_data)
{
unsigned long data;
if (copy_in_user(&hist_data32->block,
&hist_data->block,
sizeof(uint32_t)) ||
copy_in_user(&hist_data32->bin_cnt,
&hist_data->bin_cnt,
sizeof(uint32_t)))
return -EFAULT;
if (get_user(data, (unsigned long *) &hist_data->c0) ||
put_user((compat_caddr_t) data, &hist_data32->c0) ||
get_user(data, (unsigned long *) &hist_data->c1) ||
put_user((compat_caddr_t) data, &hist_data32->c1) ||
get_user(data, (unsigned long *) &hist_data->c2) ||
put_user((compat_caddr_t) data, &hist_data32->c2) ||
get_user(data, (unsigned long *) &hist_data->extra_info) ||
put_user((compat_caddr_t) data, &hist_data32->extra_info))
return -EFAULT;
return 0;
}
static int mdss_histo_compat_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg, struct file *file)
{
struct mdp_histogram_data __user *hist;
struct mdp_histogram_data32 __user *hist32;
struct mdp_histogram_start_req __user *hist_req;
struct mdp_histogram_start_req32 __user *hist_req32;
int ret = 0;
switch (cmd) {
case MSMFB_HISTOGRAM_START:
hist_req32 = compat_ptr(arg);
hist_req = compat_alloc_user_space(
sizeof(struct mdp_histogram_start_req));
if (!hist_req) {
pr_err("%s:%u: compat alloc error [%zu] bytes\n",
__func__, __LINE__,
sizeof(struct mdp_histogram_start_req));
return -EINVAL;
}
memset(hist_req, 0, sizeof(struct mdp_histogram_start_req));
ret = __from_user_hist_start_req(hist_req32, hist_req);
if (ret)
goto histo_compat_err;
ret = mdss_fb_do_ioctl(info, cmd,
(unsigned long) hist_req, file);
break;
case MSMFB_HISTOGRAM_STOP:
ret = mdss_fb_do_ioctl(info, cmd, arg, file);
break;
case MSMFB_HISTOGRAM:
hist32 = compat_ptr(arg);
hist = compat_alloc_user_space(
sizeof(struct mdp_histogram_data));
if (!hist) {
pr_err("%s:%u: compat alloc error [%zu] bytes\n",
__func__, __LINE__,
sizeof(struct mdp_histogram_data));
return -EINVAL;
}
memset(hist, 0, sizeof(struct mdp_histogram_data));
ret = __from_user_hist_data(hist32, hist);
if (ret)
goto histo_compat_err;
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) hist, file);
if (ret)
goto histo_compat_err;
ret = __to_user_hist_data(hist32, hist);
break;
default:
break;
}
histo_compat_err:
return ret;
}
static int __copy_layer_pp_info_qseed_params(
struct mdp_overlay_pp_params *pp_info,
struct mdp_overlay_pp_params32 *pp_info32)
{
pp_info->qseed_cfg[0].table_num = pp_info32->qseed_cfg[0].table_num;
pp_info->qseed_cfg[0].ops = pp_info32->qseed_cfg[0].ops;
pp_info->qseed_cfg[0].len = pp_info32->qseed_cfg[0].len;
pp_info->qseed_cfg[0].data = compat_ptr(pp_info32->qseed_cfg[0].data);
pp_info->qseed_cfg[1].table_num = pp_info32->qseed_cfg[1].table_num;
pp_info->qseed_cfg[1].ops = pp_info32->qseed_cfg[1].ops;
pp_info->qseed_cfg[1].len = pp_info32->qseed_cfg[1].len;
pp_info->qseed_cfg[1].data = compat_ptr(pp_info32->qseed_cfg[1].data);
return 0;
}
static int __copy_layer_igc_lut_data_v1_7(
struct mdp_igc_lut_data_v1_7 *cfg_payload,
struct mdp_igc_lut_data_v1_7_32 __user *cfg_payload32)
{
struct mdp_igc_lut_data_v1_7_32 local_cfg_payload32;
int ret = 0;
ret = copy_from_user(&local_cfg_payload32,
cfg_payload32,
sizeof(struct mdp_igc_lut_data_v1_7_32));
if (ret) {
pr_err("copy from user failed, IGC cfg payload = %pK\n",
cfg_payload32);
ret = -EFAULT;
goto exit;
}
cfg_payload->table_fmt = local_cfg_payload32.table_fmt;
cfg_payload->len = local_cfg_payload32.len;
cfg_payload->c0_c1_data = compat_ptr(local_cfg_payload32.c0_c1_data);
cfg_payload->c2_data = compat_ptr(local_cfg_payload32.c2_data);
exit:
return ret;
}
static int __copy_layer_pp_info_igc_params(
struct mdp_overlay_pp_params *pp_info,
struct mdp_overlay_pp_params32 *pp_info32)
{
void *cfg_payload = NULL;
uint32_t payload_size = 0;
int ret = 0;
pp_info->igc_cfg.block = pp_info32->igc_cfg.block;
pp_info->igc_cfg.version = pp_info32->igc_cfg.version;
pp_info->igc_cfg.ops = pp_info32->igc_cfg.ops;
if (pp_info->igc_cfg.version != 0) {
payload_size = __pp_compat_size_igc();
cfg_payload = kmalloc(payload_size, GFP_KERNEL);
if (!cfg_payload) {
ret = -ENOMEM;
goto exit;
}
}
switch (pp_info->igc_cfg.version) {
case mdp_igc_v1_7:
ret = __copy_layer_igc_lut_data_v1_7(cfg_payload,
compat_ptr(pp_info32->igc_cfg.cfg_payload));
if (ret) {
pr_err("compat copy of IGC cfg payload failed, ret %d\n",
ret);
kfree(cfg_payload);
cfg_payload = NULL;
goto exit;
}
break;
default:
pr_debug("No version set, fallback to legacy IGC version\n");
pp_info->igc_cfg.len = pp_info32->igc_cfg.len;
pp_info->igc_cfg.c0_c1_data =
compat_ptr(pp_info32->igc_cfg.c0_c1_data);
pp_info->igc_cfg.c2_data =
compat_ptr(pp_info32->igc_cfg.c2_data);
cfg_payload = NULL;
break;
}
exit:
pp_info->igc_cfg.cfg_payload = cfg_payload;
return ret;
}
static int __copy_layer_hist_lut_data_v1_7(
struct mdp_hist_lut_data_v1_7 *cfg_payload,
struct mdp_hist_lut_data_v1_7_32 __user *cfg_payload32)
{
struct mdp_hist_lut_data_v1_7_32 local_cfg_payload32;
int ret = 0;
ret = copy_from_user(&local_cfg_payload32,
cfg_payload32,
sizeof(struct mdp_hist_lut_data_v1_7_32));
if (ret) {
pr_err("copy from user failed, hist lut cfg_payload = %pK\n",
cfg_payload32);
ret = -EFAULT;
goto exit;
}
cfg_payload->len = local_cfg_payload32.len;
cfg_payload->data = compat_ptr(local_cfg_payload32.data);
exit:
return ret;
}
static int __copy_layer_pp_info_hist_lut_params(
struct mdp_overlay_pp_params *pp_info,
struct mdp_overlay_pp_params32 *pp_info32)
{
void *cfg_payload = NULL;
uint32_t payload_size = 0;
int ret = 0;
pp_info->hist_lut_cfg.block = pp_info32->hist_lut_cfg.block;
pp_info->hist_lut_cfg.version = pp_info32->hist_lut_cfg.version;
pp_info->hist_lut_cfg.ops = pp_info32->hist_lut_cfg.ops;
pp_info->hist_lut_cfg.hist_lut_first =
pp_info32->hist_lut_cfg.hist_lut_first;
if (pp_info->hist_lut_cfg.version != 0) {
payload_size = __pp_compat_size_hist_lut();
cfg_payload = kmalloc(payload_size, GFP_KERNEL);
if (!cfg_payload) {
ret = -ENOMEM;
goto exit;
}
}
switch (pp_info->hist_lut_cfg.version) {
case mdp_hist_lut_v1_7:
ret = __copy_layer_hist_lut_data_v1_7(cfg_payload,
compat_ptr(pp_info32->hist_lut_cfg.cfg_payload));
if (ret) {
pr_err("compat copy of Hist LUT cfg payload failed, ret %d\n",
ret);
kfree(cfg_payload);
cfg_payload = NULL;
goto exit;
}
break;
default:
pr_debug("version invalid, fallback to legacy\n");
pp_info->hist_lut_cfg.len = pp_info32->hist_lut_cfg.len;
pp_info->hist_lut_cfg.data =
compat_ptr(pp_info32->hist_lut_cfg.data);
cfg_payload = NULL;
break;
}
exit:
pp_info->hist_lut_cfg.cfg_payload = cfg_payload;
return ret;
}
static int __copy_layer_pa_data_v1_7(
struct mdp_pa_data_v1_7 *cfg_payload,
struct mdp_pa_data_v1_7_32 __user *cfg_payload32)
{
struct mdp_pa_data_v1_7_32 local_cfg_payload32;
int ret = 0;
ret = copy_from_user(&local_cfg_payload32,
cfg_payload32,
sizeof(struct mdp_pa_data_v1_7_32));
if (ret) {
pr_err("copy from user failed, pa cfg_payload = %pK\n",
cfg_payload32);
ret = -EFAULT;
goto exit;
}
cfg_payload->mode = local_cfg_payload32.mode;
cfg_payload->global_hue_adj = local_cfg_payload32.global_hue_adj;
cfg_payload->global_sat_adj = local_cfg_payload32.global_sat_adj;
cfg_payload->global_val_adj = local_cfg_payload32.global_val_adj;
cfg_payload->global_cont_adj = local_cfg_payload32.global_cont_adj;
memcpy(&cfg_payload->skin_cfg, &local_cfg_payload32.skin_cfg,
sizeof(struct mdp_pa_mem_col_data_v1_7));
memcpy(&cfg_payload->sky_cfg, &local_cfg_payload32.sky_cfg,
sizeof(struct mdp_pa_mem_col_data_v1_7));
memcpy(&cfg_payload->fol_cfg, &local_cfg_payload32.fol_cfg,
sizeof(struct mdp_pa_mem_col_data_v1_7));
cfg_payload->six_zone_thresh = local_cfg_payload32.six_zone_thresh;
cfg_payload->six_zone_adj_p0 = local_cfg_payload32.six_zone_adj_p0;
cfg_payload->six_zone_adj_p1 = local_cfg_payload32.six_zone_adj_p1;
cfg_payload->six_zone_sat_hold = local_cfg_payload32.six_zone_sat_hold;
cfg_payload->six_zone_val_hold = local_cfg_payload32.six_zone_val_hold;
cfg_payload->six_zone_len = local_cfg_payload32.six_zone_len;
cfg_payload->six_zone_curve_p0 =
compat_ptr(local_cfg_payload32.six_zone_curve_p0);
cfg_payload->six_zone_curve_p1 =
compat_ptr(local_cfg_payload32.six_zone_curve_p1);
exit:
return ret;
}
static int __copy_layer_pp_info_pa_v2_params(
struct mdp_overlay_pp_params *pp_info,
struct mdp_overlay_pp_params32 *pp_info32)
{
void *cfg_payload = NULL;
uint32_t payload_size = 0;
int ret = 0;
pp_info->pa_v2_cfg_data.block = pp_info32->pa_v2_cfg_data.block;
pp_info->pa_v2_cfg_data.version = pp_info32->pa_v2_cfg_data.version;
pp_info->pa_v2_cfg_data.flags = pp_info32->pa_v2_cfg_data.flags;
if (pp_info->pa_v2_cfg_data.version != 0) {
payload_size = __pp_compat_size_pa();
cfg_payload = kmalloc(payload_size, GFP_KERNEL);
if (!cfg_payload) {
ret = -ENOMEM;
goto exit;
}
}
switch (pp_info->pa_v2_cfg_data.version) {
case mdp_pa_v1_7:
ret = __copy_layer_pa_data_v1_7(cfg_payload,
compat_ptr(pp_info32->pa_v2_cfg_data.cfg_payload));
if (ret) {
pr_err("compat copy of PA cfg payload failed, ret %d\n",
ret);
kfree(cfg_payload);
cfg_payload = NULL;
goto exit;
}
break;
default:
pr_debug("version invalid\n");
cfg_payload = NULL;
break;
}
exit:
pp_info->pa_v2_cfg_data.cfg_payload = cfg_payload;
return ret;
}
static int __copy_layer_pp_info_legacy_pa_v2_params(
struct mdp_overlay_pp_params *pp_info,
struct mdp_overlay_pp_params32 *pp_info32)
{
pp_info->pa_v2_cfg.global_hue_adj =
pp_info32->pa_v2_cfg.global_hue_adj;
pp_info->pa_v2_cfg.global_sat_adj =
pp_info32->pa_v2_cfg.global_sat_adj;
pp_info->pa_v2_cfg.global_val_adj =
pp_info32->pa_v2_cfg.global_val_adj;
pp_info->pa_v2_cfg.global_cont_adj =
pp_info32->pa_v2_cfg.global_cont_adj;
memcpy(&pp_info->pa_v2_cfg.skin_cfg,
&pp_info32->pa_v2_cfg.skin_cfg,
sizeof(struct mdp_pa_mem_col_cfg));
memcpy(&pp_info->pa_v2_cfg.sky_cfg,
&pp_info32->pa_v2_cfg.sky_cfg,
sizeof(struct mdp_pa_mem_col_cfg));
memcpy(&pp_info->pa_v2_cfg.fol_cfg,
&pp_info32->pa_v2_cfg.fol_cfg,
sizeof(struct mdp_pa_mem_col_cfg));
pp_info->pa_v2_cfg.six_zone_thresh =
pp_info32->pa_v2_cfg.six_zone_thresh;
pp_info->pa_v2_cfg.six_zone_len =
pp_info32->pa_v2_cfg.six_zone_len;
pp_info->pa_v2_cfg.six_zone_curve_p0 =
compat_ptr(pp_info32->pa_v2_cfg.six_zone_curve_p0);
pp_info->pa_v2_cfg.six_zone_curve_p1 =
compat_ptr(pp_info32->pa_v2_cfg.six_zone_curve_p1);
return 0;
}
static int __copy_layer_pp_info_pcc_params(
struct mdp_overlay_pp_params *pp_info,
struct mdp_overlay_pp_params32 *pp_info32)
{
void *cfg_payload = NULL;
uint32_t payload_size = 0;
int ret = 0;
pp_info->pcc_cfg_data.block = pp_info32->pcc_cfg_data.block;
pp_info->pcc_cfg_data.version = pp_info32->pcc_cfg_data.version;
pp_info->pcc_cfg_data.ops = pp_info32->pcc_cfg_data.ops;
if (pp_info->pcc_cfg_data.version != 0) {
payload_size = __pp_compat_size_pcc();
cfg_payload = kmalloc(payload_size, GFP_KERNEL);
if (!cfg_payload) {
ret = -ENOMEM;
goto exit;
}
}
switch (pp_info->pcc_cfg_data.version) {
case mdp_pcc_v1_7:
ret = copy_from_user(cfg_payload,
compat_ptr(pp_info32->pcc_cfg_data.cfg_payload),
sizeof(struct mdp_pcc_data_v1_7));
if (ret) {
pr_err("compat copy of PCC cfg payload failed, ptr %pK\n",
compat_ptr(
pp_info32->pcc_cfg_data.cfg_payload));
ret = -EFAULT;
kfree(cfg_payload);
cfg_payload = NULL;
goto exit;
}
break;
default:
pr_debug("version invalid, fallback to legacy\n");
cfg_payload = NULL;
break;
}
exit:
pp_info->pcc_cfg_data.cfg_payload = cfg_payload;
return ret;
}
static int __copy_layer_pp_info_params(struct mdp_input_layer *layer,
struct mdp_input_layer32 *layer32)
{
struct mdp_overlay_pp_params *pp_info;
struct mdp_overlay_pp_params32 pp_info32;
int ret = 0;
if (!(layer->flags & MDP_LAYER_PP))
return 0;
ret = copy_from_user(&pp_info32,
compat_ptr(layer32->pp_info),
sizeof(struct mdp_overlay_pp_params32));
if (ret) {
pr_err("pp info copy from user failed, pp_info %pK\n",
compat_ptr(layer32->pp_info));
ret = -EFAULT;
goto exit;
}
pp_info = kmalloc(sizeof(struct mdp_overlay_pp_params), GFP_KERNEL);
if (!pp_info) {
ret = -ENOMEM;
goto exit;
}
memset(pp_info, 0, sizeof(struct mdp_overlay_pp_params));
pp_info->config_ops = pp_info32.config_ops;
memcpy(&pp_info->csc_cfg, &pp_info32.csc_cfg,
sizeof(struct mdp_csc_cfg));
memcpy(&pp_info->sharp_cfg, &pp_info32.sharp_cfg,
sizeof(struct mdp_sharp_cfg));
memcpy(&pp_info->hist_cfg, &pp_info32.hist_cfg,
sizeof(struct mdp_histogram_cfg));
memcpy(&pp_info->pa_cfg, &pp_info32.pa_cfg,
sizeof(struct mdp_pa_cfg));
ret = __copy_layer_pp_info_qseed_params(pp_info, &pp_info32);
if (ret) {
pr_err("compat copy pp_info QSEED params failed, ret %d\n",
ret);
goto exit_pp_info;
}
ret = __copy_layer_pp_info_legacy_pa_v2_params(pp_info, &pp_info32);
if (ret) {
pr_err("compat copy pp_info Legacy PAv2 params failed, ret %d\n",
ret);
goto exit_pp_info;
}
ret = __copy_layer_pp_info_igc_params(pp_info, &pp_info32);
if (ret) {
pr_err("compat copy pp_info IGC params failed, ret %d\n",
ret);
goto exit_pp_info;
}
ret = __copy_layer_pp_info_hist_lut_params(pp_info, &pp_info32);
if (ret) {
pr_err("compat copy pp_info Hist LUT params failed, ret %d\n",
ret);
goto exit_igc;
}
ret = __copy_layer_pp_info_pa_v2_params(pp_info, &pp_info32);
if (ret) {
pr_err("compat copy pp_info PAv2 params failed, ret %d\n",
ret);
goto exit_hist_lut;
}
ret = __copy_layer_pp_info_pcc_params(pp_info, &pp_info32);
if (ret) {
pr_err("compat copy pp_info PCC params failed, ret %d\n",
ret);
goto exit_pa;
}
layer->pp_info = pp_info;
return ret;
exit_pa:
kfree(pp_info->pa_v2_cfg_data.cfg_payload);
exit_hist_lut:
kfree(pp_info->hist_lut_cfg.cfg_payload);
exit_igc:
kfree(pp_info->igc_cfg.cfg_payload);
exit_pp_info:
kfree(pp_info);
exit:
return ret;
}
static int __to_user_mdp_overlay(struct mdp_overlay32 __user *ov32,
struct mdp_overlay __user *ov)
{
int ret = 0;
ret = copy_in_user(&ov32->src, &ov->src, sizeof(ov32->src)) ||
copy_in_user(&ov32->src_rect,
&ov->src_rect, sizeof(ov32->src_rect)) ||
copy_in_user(&ov32->dst_rect,
&ov->dst_rect, sizeof(ov32->dst_rect));
if (ret)
return -EFAULT;
ret |= put_user(ov->z_order, &ov32->z_order);
ret |= put_user(ov->is_fg, &ov32->is_fg);
ret |= put_user(ov->alpha, &ov32->alpha);
ret |= put_user(ov->blend_op, &ov32->blend_op);
ret |= put_user(ov->transp_mask, &ov32->transp_mask);
ret |= put_user(ov->flags, &ov32->flags);
ret |= put_user(ov->id, &ov32->id);
ret |= put_user(ov->priority, &ov32->priority);
if (ret)
return -EFAULT;
ret = copy_in_user(&ov32->user_data, &ov->user_data,
sizeof(ov32->user_data));
if (ret)
return -EFAULT;
ret |= put_user(ov->horz_deci, &ov32->horz_deci);
ret |= put_user(ov->vert_deci, &ov32->vert_deci);
if (ret)
return -EFAULT;
ret = __to_user_pp_params(
&ov->overlay_pp_cfg,
compat_ptr((uintptr_t) &ov32->overlay_pp_cfg));
if (ret)
return -EFAULT;
ret = copy_in_user(&ov32->scale, &ov->scale,
sizeof(struct mdp_scale_data));
if (ret)
return -EFAULT;
ret = put_user(ov->frame_rate, &ov32->frame_rate);
if (ret)
return -EFAULT;
return 0;
}
static int __from_user_mdp_overlay(struct mdp_overlay *ov,
struct mdp_overlay32 __user *ov32)
{
__u32 data;
if (copy_in_user(&ov->src, &ov32->src,
sizeof(ov32->src)) ||
copy_in_user(&ov->src_rect, &ov32->src_rect,
sizeof(ov32->src_rect)) ||
copy_in_user(&ov->dst_rect, &ov32->dst_rect,
sizeof(ov32->dst_rect)))
return -EFAULT;
if (get_user(data, &ov32->z_order) ||
put_user(data, &ov->z_order) ||
get_user(data, &ov32->is_fg) ||
put_user(data, &ov->is_fg) ||
get_user(data, &ov32->alpha) ||
put_user(data, &ov->alpha) ||
get_user(data, &ov32->blend_op) ||
put_user(data, &ov->blend_op) ||
get_user(data, &ov32->transp_mask) ||
put_user(data, &ov->transp_mask) ||
get_user(data, &ov32->flags) ||
put_user(data, &ov->flags) ||
get_user(data, &ov32->pipe_type) ||
put_user(data, &ov->pipe_type) ||
get_user(data, &ov32->id) ||
put_user(data, &ov->id) ||
get_user(data, &ov32->priority) ||
put_user(data, &ov->priority))
return -EFAULT;
if (copy_in_user(&ov->user_data, &ov32->user_data,
sizeof(ov32->user_data)))
return -EFAULT;
if (get_user(data, &ov32->horz_deci) ||
put_user(data, &ov->horz_deci) ||
get_user(data, &ov32->vert_deci) ||
put_user(data, &ov->vert_deci))
return -EFAULT;
if (__from_user_pp_params(
compat_ptr((uintptr_t) &ov32->overlay_pp_cfg),
&ov->overlay_pp_cfg))
return -EFAULT;
if (copy_in_user(&ov->scale, &ov32->scale,
sizeof(struct mdp_scale_data)))
return -EFAULT;
if (get_user(data, &ov32->frame_rate) ||
put_user(data, &ov->frame_rate))
return -EFAULT;
return 0;
}
static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist,
struct mdp_overlay_list32 *ovlist32,
struct mdp_overlay **to_list_head)
{
__u32 i, ret;
unsigned long data, from_list_head;
struct mdp_overlay32 *iter;
if (!to_list_head || !ovlist32 || !ovlist) {
pr_err("%s:%u: null error\n", __func__, __LINE__);
return -EINVAL;
}
if (copy_in_user(&ovlist->num_overlays, &ovlist32->num_overlays,
sizeof(ovlist32->num_overlays)))
return -EFAULT;
if (copy_in_user(&ovlist->flags, &ovlist32->flags,
sizeof(ovlist32->flags)))
return -EFAULT;
if (copy_in_user(&ovlist->processed_overlays,
&ovlist32->processed_overlays,
sizeof(ovlist32->processed_overlays)))
return -EFAULT;
if (get_user(data, &ovlist32->overlay_list)) {
ret = -EFAULT;
goto validate_exit;
}
for (i = 0; i < ovlist32->num_overlays; i++) {
if (get_user(from_list_head, (__u32 *)data + i)) {
ret = -EFAULT;
goto validate_exit;
}
iter = compat_ptr(from_list_head);
if (__from_user_mdp_overlay(to_list_head[i],
(struct mdp_overlay32 *)(iter))) {
ret = -EFAULT;
goto validate_exit;
}
}
ovlist->overlay_list = to_list_head;
return 0;
validate_exit:
pr_err("%s: %u: copy error\n", __func__, __LINE__);
return -EFAULT;
}
static int __to_user_mdp_overlaylist(struct mdp_overlay_list32 *ovlist32,
struct mdp_overlay_list *ovlist,
struct mdp_overlay **l_ptr)
{
__u32 i, ret;
unsigned long data, data1;
struct mdp_overlay32 *temp;
struct mdp_overlay *l = l_ptr[0];
if (copy_in_user(&ovlist32->num_overlays, &ovlist->num_overlays,
sizeof(ovlist32->num_overlays)))
return -EFAULT;
if (get_user(data, &ovlist32->overlay_list)) {
ret = -EFAULT;
pr_err("%s:%u: err\n", __func__, __LINE__);
goto validate_exit;
}
for (i = 0; i < ovlist32->num_overlays; i++) {
if (get_user(data1, (__u32 *)data + i)) {
ret = -EFAULT;
goto validate_exit;
}
temp = compat_ptr(data1);
if (__to_user_mdp_overlay(
(struct mdp_overlay32 *) temp,
l + i)) {
ret = -EFAULT;
goto validate_exit;
}
}
if (copy_in_user(&ovlist32->flags, &ovlist->flags,
sizeof(ovlist32->flags)))
return -EFAULT;
if (copy_in_user(&ovlist32->processed_overlays,
&ovlist->processed_overlays,
sizeof(ovlist32->processed_overlays)))
return -EFAULT;
return 0;
validate_exit:
pr_err("%s: %u: copy error\n", __func__, __LINE__);
return -EFAULT;
}
void mdss_compat_align_list(void __user *total_mem_chunk,
struct mdp_overlay __user **list_ptr, u32 num_ov)
{
int i = 0;
struct mdp_overlay __user *contig_overlays;
contig_overlays = total_mem_chunk + sizeof(struct mdp_overlay_list) +
(num_ov * sizeof(struct mdp_overlay *));
for (i = 0; i < num_ov; i++)
list_ptr[i] = contig_overlays + i;
}
static u32 __pp_sspp_size(void)
{
u32 size = 0;
/* pick the largest of the revision when multiple revs are supported */
size = sizeof(struct mdp_igc_lut_data_v1_7);
size += sizeof(struct mdp_pa_data_v1_7);
size += sizeof(struct mdp_pcc_data_v1_7);
size += sizeof(struct mdp_hist_lut_data_v1_7);
return size;
}
static int __pp_sspp_set_offsets(struct mdp_overlay *ov)
{
if (!ov) {
pr_err("invalid overlay pointer\n");
return -EFAULT;
}
ov->overlay_pp_cfg.igc_cfg.cfg_payload = (void *)((unsigned long)ov +
sizeof(struct mdp_overlay));
ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload =
ov->overlay_pp_cfg.igc_cfg.cfg_payload +
sizeof(struct mdp_igc_lut_data_v1_7);
ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload =
ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload +
sizeof(struct mdp_pa_data_v1_7);
ov->overlay_pp_cfg.hist_lut_cfg.cfg_payload =
ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload +
sizeof(struct mdp_pcc_data_v1_7);
return 0;
}
int mdss_compat_overlay_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg, struct file *file)
{
struct mdp_overlay *ov, **layers_head;
struct mdp_overlay32 *ov32;
struct mdp_overlay_list __user *ovlist;
struct mdp_overlay_list32 __user *ovlist32;
size_t layers_refs_sz, layers_sz, prepare_sz;
void __user *total_mem_chunk;
uint32_t num_overlays;
uint32_t alloc_size = 0;
int ret;
if (!info || !info->par)
return -EINVAL;
switch (cmd) {
case MSMFB_MDP_PP:
ret = mdss_compat_pp_ioctl(info, cmd, arg, file);
break;
case MSMFB_HISTOGRAM_START:
case MSMFB_HISTOGRAM_STOP:
case MSMFB_HISTOGRAM:
ret = mdss_histo_compat_ioctl(info, cmd, arg, file);
break;
case MSMFB_OVERLAY_GET:
alloc_size += sizeof(*ov) + __pp_sspp_size();
ov = compat_alloc_user_space(alloc_size);
if (!ov) {
pr_err("%s:%u: compat alloc error [%zu] bytes\n",
__func__, __LINE__, sizeof(*ov));
return -EINVAL;
}
ov32 = compat_ptr(arg);
ret = __pp_sspp_set_offsets(ov);
if (ret) {
pr_err("setting the pp offsets failed ret %d\n", ret);
return ret;
}
ret = __from_user_mdp_overlay(ov, ov32);
if (ret)
pr_err("%s: compat mdp overlay failed\n", __func__);
else
ret = mdss_fb_do_ioctl(info, cmd,
(unsigned long) ov, file);
ret = __to_user_mdp_overlay(ov32, ov);
break;
case MSMFB_OVERLAY_SET:
alloc_size += sizeof(*ov) + __pp_sspp_size();
ov = compat_alloc_user_space(alloc_size);
if (!ov) {
pr_err("%s:%u: compat alloc error [%zu] bytes\n",
__func__, __LINE__, sizeof(*ov));
return -EINVAL;
}
ret = __pp_sspp_set_offsets(ov);
if (ret) {
pr_err("setting the pp offsets failed ret %d\n", ret);
return ret;
}
ov32 = compat_ptr(arg);
ret = __from_user_mdp_overlay(ov, ov32);
if (ret) {
pr_err("%s: compat mdp overlay failed\n", __func__);
} else {
ret = mdss_fb_do_ioctl(info, cmd,
(unsigned long) ov, file);
ret = __to_user_mdp_overlay(ov32, ov);
}
break;
case MSMFB_OVERLAY_PREPARE:
ovlist32 = compat_ptr(arg);
if (get_user(num_overlays, &ovlist32->num_overlays)) {
pr_err("compat mdp prepare failed: invalid arg\n");
return -EFAULT;
}
if (num_overlays >= OVERLAY_MAX) {
pr_err("%s: No: of overlays exceeds max\n", __func__);
return -EINVAL;
}
layers_sz = num_overlays * sizeof(struct mdp_overlay);
prepare_sz = sizeof(struct mdp_overlay_list);
layers_refs_sz = num_overlays * sizeof(struct mdp_overlay *);
total_mem_chunk = compat_alloc_user_space(
prepare_sz + layers_refs_sz + layers_sz);
if (!total_mem_chunk) {
pr_err("%s:%u: compat alloc error [%zu] bytes\n",
__func__, __LINE__,
layers_refs_sz + layers_sz + prepare_sz);
return -EINVAL;
}
layers_head = total_mem_chunk + prepare_sz;
mdss_compat_align_list(total_mem_chunk, layers_head,
num_overlays);
ovlist = (struct mdp_overlay_list *)total_mem_chunk;
ret = __from_user_mdp_overlaylist(ovlist, ovlist32,
layers_head);
if (ret) {
pr_err("compat mdp overlaylist failed\n");
} else {
ret = mdss_fb_do_ioctl(info, cmd,
(unsigned long) ovlist, file);
if (!ret)
ret = __to_user_mdp_overlaylist(ovlist32,
ovlist, layers_head);
}
break;
case MSMFB_OVERLAY_UNSET:
case MSMFB_OVERLAY_PLAY:
case MSMFB_OVERLAY_VSYNC_CTRL:
case MSMFB_METADATA_SET:
case MSMFB_METADATA_GET:
default:
pr_debug("%s: overlay ioctl cmd=[%u]\n", __func__, cmd);
ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) arg, file);
break;
}
return ret;
}
/*
* mdss_fb_compat_ioctl() - MDSS Framebuffer compat ioctl function
* @info: pointer to framebuffer info
* @cmd: ioctl command
* @arg: argument to ioctl
*
* This function adds the compat translation layer for framebuffer
* ioctls to allow 32-bit userspace call ioctls on the mdss
* framebuffer device driven in 64-bit kernel.
*/
int mdss_fb_compat_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg, struct file *file)
{
int ret;
if (!info || !info->par)
return -EINVAL;
cmd = __do_compat_ioctl_nr(cmd);
switch (cmd) {
case MSMFB_CURSOR:
ret = mdss_fb_compat_cursor(info, cmd, arg, file);
break;
case MSMFB_SET_LUT:
ret = mdss_fb_compat_set_lut(info, arg, file);
break;
case MSMFB_BUFFER_SYNC:
ret = mdss_fb_compat_buf_sync(info, cmd, arg, file);
break;
case MSMFB_ATOMIC_COMMIT:
ret = __compat_atomic_commit(info, cmd, arg, file);
break;
case MSMFB_ASYNC_POSITION_UPDATE:
ret = __compat_async_position_update(info, cmd, arg);
break;
case MSMFB_MDP_PP:
case MSMFB_HISTOGRAM_START:
case MSMFB_HISTOGRAM_STOP:
case MSMFB_HISTOGRAM:
case MSMFB_OVERLAY_GET:
case MSMFB_OVERLAY_SET:
case MSMFB_OVERLAY_UNSET:
case MSMFB_OVERLAY_PLAY:
case MSMFB_OVERLAY_VSYNC_CTRL:
case MSMFB_METADATA_SET:
case MSMFB_METADATA_GET:
case MSMFB_OVERLAY_PREPARE:
ret = mdss_compat_overlay_ioctl(info, cmd, arg, file);
break;
case MSMFB_NOTIFY_UPDATE:
case MSMFB_DISPLAY_COMMIT:
default:
ret = mdss_fb_do_ioctl(info, cmd, arg, file);
break;
}
if (ret == -ENOSYS)
pr_err("%s: unsupported ioctl\n", __func__);
else if (ret)
pr_debug("%s: ioctl err cmd=%u ret=%d\n", __func__, cmd, ret);
return ret;
}
EXPORT_SYMBOL(mdss_fb_compat_ioctl);