/* * Copyright (C) 2017 Samsung Electronics Co.Ltd * Authors: * Marek Szyprowski <m.szyprowski@samsung.com> * * Exynos DRM Image Post Processing (IPP) related functions * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software.
*/
/** * exynos_drm_ipp_get_res_ioctl - enumerate all ipp modules * @dev: DRM device * @data: ioctl data * @file_priv: DRM file info * * Construct a list of ipp ids. * * Called by the user via ioctl. * * Returns: * Zero on success, negative errno on failure.
*/ int exynos_drm_ipp_get_res_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{ struct drm_exynos_ioctl_ipp_get_res *resp = data; struct exynos_drm_ipp *ipp;
uint32_t __user *ipp_ptr = (uint32_t __user *)
(unsignedlong)resp->ipp_id_ptr; unsignedint count = num_ipp, copied = 0;
/* * This ioctl is called twice, once to determine how much space is * needed, and the 2nd time to fill it.
*/ if (count && resp->count_ipps >= count) {
list_for_each_entry(ipp, &ipp_list, head) { if (put_user(ipp->id, ipp_ptr + copied)) return -EFAULT;
copied++;
}
}
resp->count_ipps = count;
/* * This ioctl is called twice, once to determine how much space is * needed, and the 2nd time to fill it.
*/ if (resp->formats_count >= ipp->num_formats) { for (i = 0; i < ipp->num_formats; i++) { struct drm_exynos_ipp_format tmp = {
.fourcc = ipp->formats[i].fourcc,
.type = ipp->formats[i].type,
.modifier = ipp->formats[i].modifier,
};
for (i = 0; i < ipp->num_formats; i++) { if ((ipp->formats[i].type & type) &&
ipp->formats[i].fourcc == fourcc &&
ipp->formats[i].modifier == mod) return &ipp->formats[i];
} return NULL;
}
/** * exynos_drm_ipp_get_limits_ioctl - get ipp module limits * @dev: DRM device * @data: ioctl data * @file_priv: DRM file info * * Construct a structure describing ipp module limitations for provided * picture format. * * Called by the user via ioctl. * * Returns: * Zero on success, negative errno on failure.
*/ int exynos_drm_ipp_get_limits_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{ struct drm_exynos_ioctl_ipp_get_limits *resp = data; void __user *ptr = (void __user *)(unsignedlong)resp->limits_ptr; conststruct exynos_drm_ipp_formats *format; struct exynos_drm_ipp *ipp;
if (resp->type != DRM_EXYNOS_IPP_FORMAT_SOURCE &&
resp->type != DRM_EXYNOS_IPP_FORMAT_DESTINATION) return -EINVAL;
ipp = __ipp_get(resp->ipp_id); if (!ipp) return -ENOENT;
format = __ipp_format_get(ipp, resp->fourcc, resp->modifier,
resp->type); if (!format) return -EINVAL;
/* * This ioctl is called twice, once to determine how much space is * needed, and the 2nd time to fill it.
*/ if (format->num_limits && resp->limits_count >= format->num_limits) if (copy_to_user((void __user *)ptr, format->limits, sizeof(*format->limits) * format->num_limits)) return -EFAULT;
resp->limits_count = format->num_limits;
while (size) { if (get_user(id, (uint32_t __user *)params)) return -EFAULT;
for (i = 0; i < ARRAY_SIZE(exynos_drm_ipp_params_maps); i++) if (map[i].id == id) break; if (i == ARRAY_SIZE(exynos_drm_ipp_params_maps) ||
map[i].size > size) return -EINVAL;
if (copy_from_user((void *)task + map[i].offset, params,
map[i].size)) return -EFAULT;
/** * exynos_drm_ipp_task_done - finish given task and set return code * @task: ipp task to finish * @ret: error code or 0 if operation has been performed successfully
*/ void exynos_drm_ipp_task_done(struct exynos_drm_ipp_task *task, int ret)
{ struct exynos_drm_ipp *ipp = task->ipp; unsignedlong flags;
spin_lock_irqsave(&ipp->lock, flags); if (task->flags & DRM_EXYNOS_IPP_TASK_DONE) { /* already completed task */
exynos_drm_ipp_task_cleanup(task);
} elseif (ipp->task != task) { /* task has not been scheduled for execution yet */
list_del_init(&task->head);
exynos_drm_ipp_task_cleanup(task);
} else { /* * currently processed task, call abort() and perform * cleanup with async worker
*/
task->flags |= DRM_EXYNOS_IPP_TASK_ASYNC;
spin_unlock_irqrestore(&ipp->lock, flags); if (ipp->funcs->abort)
ipp->funcs->abort(ipp, task); return;
}
spin_unlock_irqrestore(&ipp->lock, flags);
}
/** * exynos_drm_ipp_commit_ioctl - perform image processing operation * @dev: DRM device * @data: ioctl data * @file_priv: DRM file info * * Construct a ipp task from the set of properties provided from the user * and try to schedule it to framebuffer processor hardware. * * Called by the user via ioctl. * * Returns: * Zero on success, negative errno on failure.
*/ int exynos_drm_ipp_commit_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{ struct drm_exynos_ioctl_ipp_commit *arg = data; struct exynos_drm_ipp *ipp; struct exynos_drm_ipp_task *task; int ret = 0;
if ((arg->flags & ~DRM_EXYNOS_IPP_FLAGS) || arg->reserved) return -EINVAL;
/* can't test and expect an event at the same time */ if ((arg->flags & DRM_EXYNOS_IPP_FLAG_TEST_ONLY) &&
(arg->flags & DRM_EXYNOS_IPP_FLAG_EVENT)) return -EINVAL;
ipp = __ipp_get(arg->ipp_id); if (!ipp) return -ENOENT;
task = exynos_drm_ipp_task_alloc(ipp); if (!task) return -ENOMEM;
ret = exynos_drm_ipp_task_set(task, arg); if (ret) goto free;
ret = exynos_drm_ipp_task_check(task); if (ret) goto free;
ret = exynos_drm_ipp_task_setup_buffers(task, file_priv); if (ret || arg->flags & DRM_EXYNOS_IPP_FLAG_TEST_ONLY) goto free;
if (arg->flags & DRM_EXYNOS_IPP_FLAG_EVENT) {
ret = exynos_drm_ipp_event_create(task, file_priv,
arg->user_data); if (ret) goto free;
}
/* * Queue task for processing on the hardware. task object will be * then freed after exynos_drm_ipp_task_done()
*/ if (arg->flags & DRM_EXYNOS_IPP_FLAG_NONBLOCK) {
DRM_DEV_DEBUG_DRIVER(ipp->dev, "ipp: %d, nonblocking processing task %p\n",
ipp->id, task);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.