/* * cursor.c: Cursor functions for tegradc ext interface. * * Copyright (c) 2011-2019, NVIDIA CORPORATION, All rights reserved. * * Author: Robert Morell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 #include "tegra_dc_ext_priv.h" /* ugh */ #include "../dc.h" #include "../dc_priv.h" #include "../dc_reg.h" int tegra_dc_ext_get_cursor(struct tegra_dc_ext_user *user) { struct tegra_dc_ext *ext = user->ext; int ret = 0; mutex_lock(&ext->cursor.lock); if (!ext->cursor.user) ext->cursor.user = user; else if (ext->cursor.user != user) ret = -EBUSY; mutex_unlock(&ext->cursor.lock); return ret; } int tegra_dc_ext_put_cursor(struct tegra_dc_ext_user *user) { struct tegra_dc_ext *ext = user->ext; int ret = 0; mutex_lock(&ext->cursor.lock); if (ext->cursor.user == user) ext->cursor.user = NULL; else ret = -EACCES; mutex_unlock(&ext->cursor.lock); return ret; } int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user, struct tegra_dc_ext_cursor_image *args) { struct tegra_dc_ext *ext = user->ext; struct tegra_dc *dc = ext->dc; struct tegra_dc_dmabuf *handle, *old_handle; dma_addr_t phys_addr; int ret; u32 extformat = TEGRA_DC_EXT_CURSOR_FORMAT_FLAGS(args->flags); u32 clrformat = TEGRA_DC_EXT_CURSOR_COLORFMT_FLAGS(args->flags); u32 fg = CURSOR_COLOR(args->foreground.r, args->foreground.g, args->foreground.b); u32 bg = CURSOR_COLOR(args->background.r, args->background.g, args->background.b); unsigned extsize = TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE(args->flags); enum tegra_dc_cursor_size size; enum tegra_dc_cursor_blend_format blendfmt; enum CURSOR_COLOR_FORMAT colorfmt; switch (extsize) { case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32: size = TEGRA_DC_CURSOR_SIZE_32X32; break; case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64: size = TEGRA_DC_CURSOR_SIZE_64X64; break; case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_128x128: size = TEGRA_DC_CURSOR_SIZE_128X128; break; case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_256x256: size = TEGRA_DC_CURSOR_SIZE_256X256; break; default: return -EINVAL; } switch (extformat) { case TEGRA_DC_EXT_CURSOR_FORMAT_2BIT_LEGACY: blendfmt = TEGRA_DC_CURSOR_FORMAT_2BIT_LEGACY; break; case TEGRA_DC_EXT_CURSOR_FORMAT_RGBA_NON_PREMULT_ALPHA: blendfmt = TEGRA_DC_CURSOR_FORMAT_RGBA_NON_PREMULT_ALPHA; break; case TEGRA_DC_EXT_CURSOR_FORMAT_RGBA_PREMULT_ALPHA: blendfmt = TEGRA_DC_CURSOR_FORMAT_RGBA_PREMULT_ALPHA; break; case TEGRA_DC_EXT_CURSOR_FORMAT_RGBA_XOR: blendfmt = TEGRA_DC_CURSOR_FORMAT_RGBA_XOR; break; default: return -EINVAL; } switch (clrformat) { case TEGRA_DC_CURSOR_COLORFMT_LEGACY: colorfmt = legacy; break; case TEGRA_DC_CURSOR_COLORFMT_R8G8B8A8: /* normal */ colorfmt = r8g8b8a8; break; case TEGRA_DC_CURSOR_COLORFMT_A1R5G5B5: colorfmt = a1r5g5b5; break; case TEGRA_DC_CURSOR_COLORFMT_A8R8G8B8: colorfmt = a8r8g8b8; break; default: return -EINVAL; } mutex_lock(&ext->cursor.lock); if (ext->cursor.user != user) { ret = -EACCES; goto unlock; } if (!ext->enabled) { ret = -ENXIO; goto unlock; } old_handle = ext->cursor.cur_handle; ret = tegra_dc_ext_pin_window(user, args->buff_id, &handle, &phys_addr); if (ret) goto unlock; tegra_dc_scrncapt_disp_pause_lock(dc); ext->cursor.cur_handle = handle; ret = tegra_dc_cursor_image(dc, blendfmt, size, fg, bg, phys_addr, colorfmt, args->alpha, args->flags, !!old_handle); tegra_dc_scrncapt_disp_pause_unlock(dc); mutex_unlock(&ext->cursor.lock); if (old_handle) { dma_buf_unmap_attachment(old_handle->attach, old_handle->sgt, DMA_TO_DEVICE); dma_buf_detach(old_handle->buf, old_handle->attach); dma_buf_put(old_handle->buf); kfree(old_handle); } return ret; unlock: mutex_unlock(&ext->cursor.lock); return ret; } int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user, struct tegra_dc_ext_cursor *args) { struct tegra_dc_ext *ext = NULL; struct tegra_dc *dc = NULL; bool enable; int ret; if (!args) return -EINVAL; if (!user || !user->ext || !user->ext->dc) return -ENODEV; ext = user->ext; dc = ext->dc; mutex_lock(&ext->cursor.lock); if (ext->cursor.user != user) { ret = -EACCES; goto unlock; } if (!ext->enabled) { ret = -ENXIO; goto unlock; } enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE); if (enable && !ext->cursor.cur_handle) { ret = -EFAULT; goto unlock; } tegra_dc_scrncapt_disp_pause_lock(dc); ret = tegra_dc_cursor_set(dc, enable, args->x, args->y); tegra_dc_scrncapt_disp_pause_unlock(dc); mutex_unlock(&ext->cursor.lock); return ret; unlock: mutex_unlock(&ext->cursor.lock); return ret; } int tegra_dc_ext_cursor_clip(struct tegra_dc_ext_user *user, int *args) { struct tegra_dc_ext *ext = user->ext; struct tegra_dc *dc = ext->dc; int ret; mutex_lock(&ext->cursor.lock); if (ext->cursor.user != user) { ret = -EACCES; goto unlock; } if (!ext->enabled) { ret = -ENXIO; goto unlock; } ret = tegra_dc_cursor_clip(dc, *args); mutex_unlock(&ext->cursor.lock); return ret; unlock: mutex_unlock(&ext->cursor.lock); return ret; }