| /* |
| * udl_cursor.c |
| * |
| * Copyright (c) 2015 The Chromium OS Authors |
| * |
| * 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. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <drm/drmP.h> |
| #include <drm/drm_crtc_helper.h> |
| |
| #include "udl_cursor.h" |
| #include "udl_drv.h" |
| |
| #define UDL_CURSOR_W 64 |
| #define UDL_CURSOR_H 64 |
| #define UDL_CURSOR_BUF (UDL_CURSOR_W * UDL_CURSOR_H) |
| |
| /* |
| * UDL drm cursor private structure. |
| */ |
| struct udl_cursor { |
| uint32_t buffer[UDL_CURSOR_BUF]; |
| bool enabled; |
| int x; |
| int y; |
| }; |
| |
| int udl_cursor_alloc(struct udl_cursor **cursor) |
| { |
| struct udl_cursor *new_cursor = kzalloc(sizeof(struct udl_cursor), |
| GFP_KERNEL); |
| if (!new_cursor) |
| return -ENOMEM; |
| *cursor = new_cursor; |
| return 0; |
| } |
| |
| void udl_cursor_free(struct udl_cursor *cursor) |
| { |
| BUG_ON(!cursor); |
| kfree(cursor); |
| } |
| |
| void udl_cursor_copy(struct udl_cursor *dst, struct udl_cursor *src) |
| { |
| memcpy(dst, src, sizeof(struct udl_cursor)); |
| } |
| |
| bool udl_cursor_enabled(struct udl_cursor *cursor) |
| { |
| return cursor->enabled; |
| } |
| |
| void udl_cursor_get_hline(struct udl_cursor *cursor, int x, int y, |
| struct udl_cursor_hline *hline) |
| { |
| if (!cursor || !cursor->enabled || |
| x >= cursor->x + UDL_CURSOR_W || |
| y < cursor->y || y >= cursor->y + UDL_CURSOR_H) { |
| hline->buffer = NULL; |
| return; |
| } |
| |
| hline->buffer = &cursor->buffer[UDL_CURSOR_W * (y - cursor->y)]; |
| hline->width = UDL_CURSOR_W; |
| hline->offset = x - cursor->x; |
| } |
| |
| /* |
| * Return pre-computed cursor blend value defined as: |
| * R: 5 bits (bit 0:4) |
| * G: 6 bits (bit 5:10) |
| * B: 5 bits (bit 11:15) |
| * A: 7 bits (bit 16:22) |
| */ |
| static uint32_t cursor_blend_val32(uint32_t pix) |
| { |
| /* range of alpha_scaled is 0..64 */ |
| uint32_t alpha_scaled = ((pix >> 24) * 65) >> 8; |
| return ((pix >> 3) & 0x1f) | |
| ((pix >> 5) & 0x7e0) | |
| ((pix >> 8) & 0xf800) | |
| (alpha_scaled << 16); |
| } |
| |
| static int udl_cursor_download(struct udl_cursor *cursor, |
| struct drm_gem_object *obj) |
| { |
| struct udl_gem_object *udl_gem_obj = to_udl_bo(obj); |
| uint32_t *src_ptr, *dst_ptr; |
| size_t i; |
| |
| int ret = udl_gem_vmap(udl_gem_obj); |
| if (ret != 0) { |
| DRM_ERROR("failed to vmap cursor\n"); |
| return ret; |
| } |
| |
| src_ptr = udl_gem_obj->vmapping; |
| dst_ptr = cursor->buffer; |
| for (i = 0; i < UDL_CURSOR_BUF; ++i) |
| dst_ptr[i] = cursor_blend_val32(le32_to_cpu(src_ptr[i])); |
| return 0; |
| } |
| |
| int udl_cursor_set(struct drm_crtc *crtc, struct drm_file *file, |
| uint32_t handle, uint32_t width, uint32_t height, |
| struct udl_cursor *cursor) |
| { |
| if (handle) { |
| struct drm_gem_object *obj; |
| int err; |
| /* Currently we only support 64x64 cursors */ |
| if (width != UDL_CURSOR_W || height != UDL_CURSOR_H) { |
| DRM_ERROR("we currently only support %dx%d cursors\n", |
| UDL_CURSOR_W, UDL_CURSOR_H); |
| return -EINVAL; |
| } |
| obj = drm_gem_object_lookup(file, handle); |
| if (!obj) { |
| DRM_ERROR("failed to lookup gem object.\n"); |
| return -EINVAL; |
| } |
| err = udl_cursor_download(cursor, obj); |
| drm_gem_object_put_locked(obj); |
| if (err != 0) { |
| DRM_ERROR("failed to copy cursor.\n"); |
| return err; |
| } |
| cursor->enabled = true; |
| } else { |
| cursor->enabled = false; |
| } |
| |
| return 0; |
| } |
| |
| int udl_cursor_move(struct drm_crtc *crtc, int x, int y, |
| struct udl_cursor *cursor) |
| { |
| cursor->x = x; |
| cursor->y = y; |
| return 0; |
| } |