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