1d722e3fbSopenharmony_ci/* 2d722e3fbSopenharmony_ci * Copyright © 2014 NVIDIA Corporation 3d722e3fbSopenharmony_ci * 4d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6d722e3fbSopenharmony_ci * to deal in the Software without restriction, including without limitation 7d722e3fbSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d722e3fbSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9d722e3fbSopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10d722e3fbSopenharmony_ci * 11d722e3fbSopenharmony_ci * The above copyright notice and this permission notice shall be included in 12d722e3fbSopenharmony_ci * all copies or substantial portions of the Software. 13d722e3fbSopenharmony_ci * 14d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15d722e3fbSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16d722e3fbSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17d722e3fbSopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18d722e3fbSopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19d722e3fbSopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20d722e3fbSopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 21d722e3fbSopenharmony_ci */ 22d722e3fbSopenharmony_ci 23d722e3fbSopenharmony_ci#ifdef HAVE_CONFIG_H 24d722e3fbSopenharmony_ci# include "config.h" 25d722e3fbSopenharmony_ci#endif 26d722e3fbSopenharmony_ci 27d722e3fbSopenharmony_ci#include <errno.h> 28d722e3fbSopenharmony_ci#include <fcntl.h> 29d722e3fbSopenharmony_ci#include <stdbool.h> 30d722e3fbSopenharmony_ci#include <stdint.h> 31d722e3fbSopenharmony_ci#include <stdio.h> 32d722e3fbSopenharmony_ci#include <stdlib.h> 33d722e3fbSopenharmony_ci#include <string.h> 34d722e3fbSopenharmony_ci#include <unistd.h> 35d722e3fbSopenharmony_ci 36d722e3fbSopenharmony_ci#include <sys/ioctl.h> 37d722e3fbSopenharmony_ci 38d722e3fbSopenharmony_ci#include "xf86drm.h" 39d722e3fbSopenharmony_ci#include "xf86drmMode.h" 40d722e3fbSopenharmony_ci#include "drm_fourcc.h" 41d722e3fbSopenharmony_ci 42d722e3fbSopenharmony_ci#include "drm-test.h" 43d722e3fbSopenharmony_ci 44d722e3fbSopenharmony_cistatic int drm_screen_probe_connector(struct drm_screen *screen, 45d722e3fbSopenharmony_ci drmModeConnectorPtr connector) 46d722e3fbSopenharmony_ci{ 47d722e3fbSopenharmony_ci drmModeEncoderPtr encoder; 48d722e3fbSopenharmony_ci drmModeCrtcPtr crtc; 49d722e3fbSopenharmony_ci drmModeFBPtr fb; 50d722e3fbSopenharmony_ci 51d722e3fbSopenharmony_ci encoder = drmModeGetEncoder(screen->fd, connector->encoder_id); 52d722e3fbSopenharmony_ci if (!encoder) 53d722e3fbSopenharmony_ci return -ENODEV; 54d722e3fbSopenharmony_ci 55d722e3fbSopenharmony_ci crtc = drmModeGetCrtc(screen->fd, encoder->crtc_id); 56d722e3fbSopenharmony_ci if (!crtc) { 57d722e3fbSopenharmony_ci drmModeFreeEncoder(encoder); 58d722e3fbSopenharmony_ci return -ENODEV; 59d722e3fbSopenharmony_ci } 60d722e3fbSopenharmony_ci 61d722e3fbSopenharmony_ci screen->old_fb = crtc->buffer_id; 62d722e3fbSopenharmony_ci 63d722e3fbSopenharmony_ci fb = drmModeGetFB(screen->fd, crtc->buffer_id); 64d722e3fbSopenharmony_ci if (!fb) { 65d722e3fbSopenharmony_ci /* TODO: create new framebuffer */ 66d722e3fbSopenharmony_ci drmModeFreeEncoder(encoder); 67d722e3fbSopenharmony_ci drmModeFreeCrtc(crtc); 68d722e3fbSopenharmony_ci return -ENOSYS; 69d722e3fbSopenharmony_ci } 70d722e3fbSopenharmony_ci 71d722e3fbSopenharmony_ci screen->connector = connector->connector_id; 72d722e3fbSopenharmony_ci screen->old_fb = crtc->buffer_id; 73d722e3fbSopenharmony_ci screen->crtc = encoder->crtc_id; 74d722e3fbSopenharmony_ci /* TODO: check crtc->mode_valid */ 75d722e3fbSopenharmony_ci screen->mode = crtc->mode; 76d722e3fbSopenharmony_ci 77d722e3fbSopenharmony_ci screen->width = fb->width; 78d722e3fbSopenharmony_ci screen->height = fb->height; 79d722e3fbSopenharmony_ci screen->pitch = fb->pitch; 80d722e3fbSopenharmony_ci screen->depth = fb->depth; 81d722e3fbSopenharmony_ci screen->bpp = fb->bpp; 82d722e3fbSopenharmony_ci 83d722e3fbSopenharmony_ci drmModeFreeEncoder(encoder); 84d722e3fbSopenharmony_ci drmModeFreeCrtc(crtc); 85d722e3fbSopenharmony_ci drmModeFreeFB(fb); 86d722e3fbSopenharmony_ci 87d722e3fbSopenharmony_ci return 0; 88d722e3fbSopenharmony_ci} 89d722e3fbSopenharmony_ci 90d722e3fbSopenharmony_ciint drm_screen_open(struct drm_screen **screenp, int fd) 91d722e3fbSopenharmony_ci{ 92d722e3fbSopenharmony_ci drmModeConnectorPtr connector; 93d722e3fbSopenharmony_ci struct drm_screen *screen; 94d722e3fbSopenharmony_ci bool found = false; 95d722e3fbSopenharmony_ci drmModeResPtr res; 96d722e3fbSopenharmony_ci unsigned int i; 97d722e3fbSopenharmony_ci int err; 98d722e3fbSopenharmony_ci 99d722e3fbSopenharmony_ci if (!screenp || fd < 0) 100d722e3fbSopenharmony_ci return -EINVAL; 101d722e3fbSopenharmony_ci 102d722e3fbSopenharmony_ci screen = calloc(1, sizeof(*screen)); 103d722e3fbSopenharmony_ci if (!screen) 104d722e3fbSopenharmony_ci return -ENOMEM; 105d722e3fbSopenharmony_ci 106d722e3fbSopenharmony_ci screen->format = DRM_FORMAT_XRGB8888; 107d722e3fbSopenharmony_ci screen->fd = fd; 108d722e3fbSopenharmony_ci 109d722e3fbSopenharmony_ci res = drmModeGetResources(fd); 110d722e3fbSopenharmony_ci if (!res) { 111d722e3fbSopenharmony_ci free(screen); 112d722e3fbSopenharmony_ci return -ENOMEM; 113d722e3fbSopenharmony_ci } 114d722e3fbSopenharmony_ci 115d722e3fbSopenharmony_ci for (i = 0; i < (unsigned int)res->count_connectors; i++) { 116d722e3fbSopenharmony_ci connector = drmModeGetConnector(fd, res->connectors[i]); 117d722e3fbSopenharmony_ci if (!connector) 118d722e3fbSopenharmony_ci continue; 119d722e3fbSopenharmony_ci 120d722e3fbSopenharmony_ci if (connector->connection != DRM_MODE_CONNECTED) { 121d722e3fbSopenharmony_ci drmModeFreeConnector(connector); 122d722e3fbSopenharmony_ci continue; 123d722e3fbSopenharmony_ci } 124d722e3fbSopenharmony_ci 125d722e3fbSopenharmony_ci err = drm_screen_probe_connector(screen, connector); 126d722e3fbSopenharmony_ci if (err < 0) { 127d722e3fbSopenharmony_ci drmModeFreeConnector(connector); 128d722e3fbSopenharmony_ci continue; 129d722e3fbSopenharmony_ci } 130d722e3fbSopenharmony_ci 131d722e3fbSopenharmony_ci drmModeFreeConnector(connector); 132d722e3fbSopenharmony_ci found = true; 133d722e3fbSopenharmony_ci break; 134d722e3fbSopenharmony_ci } 135d722e3fbSopenharmony_ci 136d722e3fbSopenharmony_ci drmModeFreeResources(res); 137d722e3fbSopenharmony_ci 138d722e3fbSopenharmony_ci if (!found) { 139d722e3fbSopenharmony_ci free(screen); 140d722e3fbSopenharmony_ci return -ENODEV; 141d722e3fbSopenharmony_ci } 142d722e3fbSopenharmony_ci 143d722e3fbSopenharmony_ci *screenp = screen; 144d722e3fbSopenharmony_ci 145d722e3fbSopenharmony_ci return 0; 146d722e3fbSopenharmony_ci} 147d722e3fbSopenharmony_ci 148d722e3fbSopenharmony_ciint drm_screen_close(struct drm_screen *screen) 149d722e3fbSopenharmony_ci{ 150d722e3fbSopenharmony_ci int err; 151d722e3fbSopenharmony_ci 152d722e3fbSopenharmony_ci err = drmModeSetCrtc(screen->fd, screen->crtc, screen->old_fb, 0, 0, 153d722e3fbSopenharmony_ci &screen->connector, 1, &screen->mode); 154d722e3fbSopenharmony_ci if (err < 0) { 155d722e3fbSopenharmony_ci fprintf(stderr, "drmModeSetCrtc() failed: %m\n"); 156d722e3fbSopenharmony_ci return -errno; 157d722e3fbSopenharmony_ci } 158d722e3fbSopenharmony_ci 159d722e3fbSopenharmony_ci free(screen); 160d722e3fbSopenharmony_ci 161d722e3fbSopenharmony_ci return 0; 162d722e3fbSopenharmony_ci} 163d722e3fbSopenharmony_ci 164d722e3fbSopenharmony_ciint drm_framebuffer_new(struct drm_framebuffer **fbp, 165d722e3fbSopenharmony_ci struct drm_screen *screen, uint32_t handle, 166d722e3fbSopenharmony_ci unsigned int width, unsigned int height, 167d722e3fbSopenharmony_ci unsigned int pitch, uint32_t format, 168d722e3fbSopenharmony_ci void *data) 169d722e3fbSopenharmony_ci{ 170d722e3fbSopenharmony_ci struct drm_framebuffer *fb; 171d722e3fbSopenharmony_ci uint32_t handles[4]; 172d722e3fbSopenharmony_ci uint32_t pitches[4]; 173d722e3fbSopenharmony_ci uint32_t offsets[4]; 174d722e3fbSopenharmony_ci int err; 175d722e3fbSopenharmony_ci 176d722e3fbSopenharmony_ci fb = calloc(1, sizeof(*fb)); 177d722e3fbSopenharmony_ci if (!fb) 178d722e3fbSopenharmony_ci return -ENOMEM; 179d722e3fbSopenharmony_ci 180d722e3fbSopenharmony_ci fb->fd = screen->fd; 181d722e3fbSopenharmony_ci fb->width = width; 182d722e3fbSopenharmony_ci fb->height = height; 183d722e3fbSopenharmony_ci fb->pitch = pitch; 184d722e3fbSopenharmony_ci fb->format = format; 185d722e3fbSopenharmony_ci fb->data = data; 186d722e3fbSopenharmony_ci 187d722e3fbSopenharmony_ci handles[0] = handle; 188d722e3fbSopenharmony_ci pitches[0] = pitch; 189d722e3fbSopenharmony_ci offsets[0] = 0; 190d722e3fbSopenharmony_ci 191d722e3fbSopenharmony_ci err = drmModeAddFB2(screen->fd, width, height, format, handles, 192d722e3fbSopenharmony_ci pitches, offsets, &fb->handle, 0); 193d722e3fbSopenharmony_ci if (err < 0) 194d722e3fbSopenharmony_ci return -errno; 195d722e3fbSopenharmony_ci 196d722e3fbSopenharmony_ci *fbp = fb; 197d722e3fbSopenharmony_ci 198d722e3fbSopenharmony_ci return 0; 199d722e3fbSopenharmony_ci} 200d722e3fbSopenharmony_ci 201d722e3fbSopenharmony_ciint drm_framebuffer_free(struct drm_framebuffer *fb) 202d722e3fbSopenharmony_ci{ 203d722e3fbSopenharmony_ci int err; 204d722e3fbSopenharmony_ci 205d722e3fbSopenharmony_ci err = drmModeRmFB(fb->fd, fb->handle); 206d722e3fbSopenharmony_ci if (err < 0) 207d722e3fbSopenharmony_ci return -errno; 208d722e3fbSopenharmony_ci 209d722e3fbSopenharmony_ci free(fb); 210d722e3fbSopenharmony_ci 211d722e3fbSopenharmony_ci return 0; 212d722e3fbSopenharmony_ci} 213d722e3fbSopenharmony_ci 214d722e3fbSopenharmony_ciint drm_screen_set_framebuffer(struct drm_screen *screen, 215d722e3fbSopenharmony_ci struct drm_framebuffer *fb) 216d722e3fbSopenharmony_ci{ 217d722e3fbSopenharmony_ci int err; 218d722e3fbSopenharmony_ci 219d722e3fbSopenharmony_ci err = drmModeSetCrtc(screen->fd, screen->crtc, fb->handle, 0, 0, 220d722e3fbSopenharmony_ci &screen->connector, 1, &screen->mode); 221d722e3fbSopenharmony_ci if (err < 0) 222d722e3fbSopenharmony_ci return -errno; 223d722e3fbSopenharmony_ci 224d722e3fbSopenharmony_ci return 0; 225d722e3fbSopenharmony_ci} 226d722e3fbSopenharmony_ci 227d722e3fbSopenharmony_ciint drm_open(const char *path) 228d722e3fbSopenharmony_ci{ 229d722e3fbSopenharmony_ci int fd, err; 230d722e3fbSopenharmony_ci 231d722e3fbSopenharmony_ci fd = open(path, O_RDWR); 232d722e3fbSopenharmony_ci if (fd < 0) 233d722e3fbSopenharmony_ci return -errno; 234d722e3fbSopenharmony_ci 235d722e3fbSopenharmony_ci err = drmSetMaster(fd); 236d722e3fbSopenharmony_ci if (err < 0) { 237d722e3fbSopenharmony_ci close(fd); 238d722e3fbSopenharmony_ci return -errno; 239d722e3fbSopenharmony_ci } 240d722e3fbSopenharmony_ci 241d722e3fbSopenharmony_ci return fd; 242d722e3fbSopenharmony_ci} 243d722e3fbSopenharmony_ci 244d722e3fbSopenharmony_civoid drm_close(int fd) 245d722e3fbSopenharmony_ci{ 246d722e3fbSopenharmony_ci drmDropMaster(fd); 247d722e3fbSopenharmony_ci close(fd); 248d722e3fbSopenharmony_ci} 249