1857b0bc6Smrg/* 2857b0bc6Smrg * DRM based mode setting test program 3857b0bc6Smrg * Copyright (C) 2013 Red Hat 4857b0bc6Smrg * Author: Rob Clark <robdclark@gmail.com> 5857b0bc6Smrg * 6857b0bc6Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7857b0bc6Smrg * copy of this software and associated documentation files (the "Software"), 8857b0bc6Smrg * to deal in the Software without restriction, including without limitation 9857b0bc6Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10857b0bc6Smrg * and/or sell copies of the Software, and to permit persons to whom the 11857b0bc6Smrg * Software is furnished to do so, subject to the following conditions: 12857b0bc6Smrg * 13857b0bc6Smrg * The above copyright notice and this permission notice shall be included in 14857b0bc6Smrg * all copies or substantial portions of the Software. 15857b0bc6Smrg * 16857b0bc6Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17857b0bc6Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18857b0bc6Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19857b0bc6Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20857b0bc6Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21857b0bc6Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22857b0bc6Smrg * IN THE SOFTWARE. 23857b0bc6Smrg */ 24857b0bc6Smrg 25857b0bc6Smrg#include <assert.h> 26857b0bc6Smrg#include <errno.h> 27857b0bc6Smrg#include <stdio.h> 28857b0bc6Smrg#include <stdlib.h> 29857b0bc6Smrg#include <stdint.h> 30857b0bc6Smrg#include <string.h> 31857b0bc6Smrg#include <signal.h> 32857b0bc6Smrg#include <sys/time.h> 3308d7334dSsnj#include <pthread.h> 3408d7334dSsnj#include <unistd.h> 35857b0bc6Smrg 36857b0bc6Smrg#include "xf86drm.h" 37857b0bc6Smrg#include "xf86drmMode.h" 38857b0bc6Smrg 393f012e29Smrg#include "util/common.h" 403f012e29Smrg 41857b0bc6Smrg#include "buffers.h" 42857b0bc6Smrg#include "cursor.h" 43857b0bc6Smrg 44857b0bc6Smrgstruct cursor { 45857b0bc6Smrg int fd; 46857b0bc6Smrg uint32_t bo_handle; 47857b0bc6Smrg uint32_t crtc_id; 48857b0bc6Smrg uint32_t crtc_w, crtc_h; 49857b0bc6Smrg uint32_t w, h; 50857b0bc6Smrg 51857b0bc6Smrg /* current state */ 52857b0bc6Smrg uint32_t enabled, x, y; 53857b0bc6Smrg int32_t dx, dy; 54857b0bc6Smrg}; 55857b0bc6Smrg 56857b0bc6Smrg#define MAX_CURSORS 8 57857b0bc6Smrgstatic struct cursor cursors[MAX_CURSORS]; 58857b0bc6Smrgstatic int ncursors; 59857b0bc6Smrg 6008d7334dSsnjstatic pthread_t cursor_thread; 6108d7334dSsnjstatic int cursor_running; 6208d7334dSsnj 63857b0bc6Smrg/* 64857b0bc6Smrg * Timer driven program loops through these steps to move/enable/disable 65857b0bc6Smrg * the cursor 66857b0bc6Smrg */ 67857b0bc6Smrg 68857b0bc6Smrgstruct cursor_step { 693f012e29Smrg void (*run)(struct cursor *cursor, const struct cursor_step *step); 70857b0bc6Smrg uint32_t msec; 71857b0bc6Smrg uint32_t repeat; 72857b0bc6Smrg int arg; 73857b0bc6Smrg}; 74857b0bc6Smrg 75857b0bc6Smrgstatic uint32_t indx, count; 76857b0bc6Smrg 773f012e29Smrgstatic void set_cursor(struct cursor *cursor, const struct cursor_step *step) 78857b0bc6Smrg{ 79857b0bc6Smrg int enabled = (step->arg ^ count) & 0x1; 80857b0bc6Smrg uint32_t handle = 0; 81857b0bc6Smrg 82857b0bc6Smrg if (enabled) 83857b0bc6Smrg handle = cursor->bo_handle; 84857b0bc6Smrg 85857b0bc6Smrg cursor->enabled = enabled; 86857b0bc6Smrg 87857b0bc6Smrg drmModeSetCursor(cursor->fd, cursor->crtc_id, handle, cursor->w, cursor->h); 88857b0bc6Smrg} 89857b0bc6Smrg 903f012e29Smrgstatic void move_cursor(struct cursor *cursor, const struct cursor_step *step) 91857b0bc6Smrg{ 92857b0bc6Smrg int x = cursor->x; 93857b0bc6Smrg int y = cursor->y; 94857b0bc6Smrg 95857b0bc6Smrg if (!cursor->enabled) 96857b0bc6Smrg drmModeSetCursor(cursor->fd, cursor->crtc_id, 97857b0bc6Smrg cursor->bo_handle, cursor->w, cursor->h); 98857b0bc6Smrg 99857b0bc6Smrg /* calculate new cursor position: */ 100857b0bc6Smrg x += cursor->dx * step->arg; 101857b0bc6Smrg y += cursor->dy * step->arg; 102857b0bc6Smrg 103857b0bc6Smrg if (x < 0) { 104857b0bc6Smrg x = 0; 105857b0bc6Smrg cursor->dx = 1; 106857b0bc6Smrg } else if (x > (int)cursor->crtc_w) { 107857b0bc6Smrg x = cursor->crtc_w - 1; 108857b0bc6Smrg cursor->dx = -1; 109857b0bc6Smrg } 110857b0bc6Smrg 111857b0bc6Smrg if (y < 0) { 112857b0bc6Smrg y = 0; 113857b0bc6Smrg cursor->dy = 1; 114857b0bc6Smrg } else if (y > (int)cursor->crtc_h) { 115857b0bc6Smrg y = cursor->crtc_h - 1; 116857b0bc6Smrg cursor->dy = -1; 117857b0bc6Smrg } 118857b0bc6Smrg 119857b0bc6Smrg cursor->x = x; 120857b0bc6Smrg cursor->y = y; 121857b0bc6Smrg 122857b0bc6Smrg drmModeMoveCursor(cursor->fd, cursor->crtc_id, x, y); 123857b0bc6Smrg} 124857b0bc6Smrg 1253f012e29Smrgstatic const struct cursor_step steps[] = { 126857b0bc6Smrg { set_cursor, 10, 0, 1 }, /* enable */ 127857b0bc6Smrg { move_cursor, 1, 100, 1 }, 128857b0bc6Smrg { move_cursor, 1, 10, 10 }, 129857b0bc6Smrg { set_cursor, 1, 100, 0 }, /* disable/enable loop */ 130857b0bc6Smrg { move_cursor, 1, 10, 10 }, 131857b0bc6Smrg { move_cursor, 9, 100, 1 }, 132857b0bc6Smrg { move_cursor, 11, 100, 5 }, 133857b0bc6Smrg { set_cursor, 17, 10, 0 }, /* disable/enable loop */ 134857b0bc6Smrg { move_cursor, 9, 100, 1 }, 135857b0bc6Smrg { set_cursor, 13, 10, 0 }, /* disable/enable loop */ 136857b0bc6Smrg { move_cursor, 9, 100, 1 }, 137857b0bc6Smrg { set_cursor, 13, 10, 0 }, /* disable/enable loop */ 138857b0bc6Smrg { set_cursor, 10, 0, 0 }, /* disable */ 139857b0bc6Smrg}; 140857b0bc6Smrg 14108d7334dSsnjstatic void *cursor_thread_func(void *data) 142857b0bc6Smrg{ 14308d7334dSsnj while (cursor_running) { 1443f012e29Smrg const struct cursor_step *step = &steps[indx % ARRAY_SIZE(steps)]; 14508d7334dSsnj int i; 14608d7334dSsnj 14708d7334dSsnj for (i = 0; i < ncursors; i++) { 14808d7334dSsnj struct cursor *cursor = &cursors[i]; 14908d7334dSsnj step->run(cursor, step); 15008d7334dSsnj } 15108d7334dSsnj 15208d7334dSsnj /* iterate to next count/step: */ 15308d7334dSsnj if (count < step->repeat) { 15408d7334dSsnj count++; 15508d7334dSsnj } else { 15608d7334dSsnj count = 0; 15708d7334dSsnj indx++; 15808d7334dSsnj } 15908d7334dSsnj 16008d7334dSsnj usleep(1000 * step->msec); 161857b0bc6Smrg } 162857b0bc6Smrg 16308d7334dSsnj return NULL; 164857b0bc6Smrg} 165857b0bc6Smrg 166857b0bc6Smrgint cursor_init(int fd, uint32_t bo_handle, uint32_t crtc_id, 167857b0bc6Smrg uint32_t crtc_w, uint32_t crtc_h, uint32_t w, uint32_t h) 168857b0bc6Smrg{ 169857b0bc6Smrg struct cursor *cursor = &cursors[ncursors]; 170857b0bc6Smrg 171857b0bc6Smrg assert(ncursors < MAX_CURSORS); 172857b0bc6Smrg 173857b0bc6Smrg cursor->fd = fd; 174857b0bc6Smrg cursor->bo_handle = bo_handle; 175857b0bc6Smrg cursor->crtc_id = crtc_id; 176857b0bc6Smrg cursor->crtc_w = crtc_w; 177857b0bc6Smrg cursor->crtc_h = crtc_h; 178857b0bc6Smrg cursor->w = w; 179857b0bc6Smrg cursor->h = h; 180857b0bc6Smrg 181857b0bc6Smrg cursor->enabled = 0; 182857b0bc6Smrg cursor->x = w/2; 183857b0bc6Smrg cursor->y = h/2; 184857b0bc6Smrg cursor->dx = 1; 185857b0bc6Smrg cursor->dy = 1; 186857b0bc6Smrg 187857b0bc6Smrg ncursors++; 188857b0bc6Smrg 189857b0bc6Smrg return 0; 190857b0bc6Smrg} 191857b0bc6Smrg 192857b0bc6Smrgint cursor_start(void) 193857b0bc6Smrg{ 19408d7334dSsnj cursor_running = 1; 19508d7334dSsnj pthread_create(&cursor_thread, NULL, cursor_thread_func, NULL); 196857b0bc6Smrg printf("starting cursor\n"); 197857b0bc6Smrg return 0; 198857b0bc6Smrg} 199857b0bc6Smrg 200857b0bc6Smrgint cursor_stop(void) 201857b0bc6Smrg{ 20208d7334dSsnj cursor_running = 0; 20308d7334dSsnj pthread_join(cursor_thread, NULL); 204857b0bc6Smrg printf("cursor stopped\n"); 205857b0bc6Smrg return 0; 206857b0bc6Smrg} 207