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 (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 #include <errno.h> 25 #include <string.h> 26 27 #include <sys/mman.h> 28 29 #include <drm_fourcc.h> 30 31 #include "xf86drm.h" 32 33 #include "libkms-test.h" 34 35 struct kms_framebuffer *kms_framebuffer_create(struct kms_device *device, 36 unsigned int width, 37 unsigned int height, 38 uint32_t format) 39 { 40 uint32_t handles[4], pitches[4], offsets[4]; 41 struct drm_mode_create_dumb args; 42 struct kms_framebuffer *fb; 43 int err; 44 45 fb = calloc(1, sizeof(*fb)); 46 if (!fb) 47 return NULL; 48 49 fb->device = device; 50 fb->width = width; 51 fb->height = height; 52 fb->format = format; 53 54 memset(&args, 0, sizeof(args)); 55 args.width = width; 56 args.height = height; 57 58 switch (format) { 59 case DRM_FORMAT_XRGB8888: 60 case DRM_FORMAT_XBGR8888: 61 case DRM_FORMAT_RGBA8888: 62 args.bpp = 32; 63 break; 64 65 default: 66 free(fb); 67 return NULL; 68 } 69 70 err = drmIoctl(device->fd, DRM_IOCTL_MODE_CREATE_DUMB, &args); 71 if (err < 0) { 72 free(fb); 73 return NULL; 74 } 75 76 fb->handle = args.handle; 77 fb->pitch = args.pitch; 78 fb->size = args.size; 79 80 handles[0] = fb->handle; 81 pitches[0] = fb->pitch; 82 offsets[0] = 0; 83 84 err = drmModeAddFB2(device->fd, width, height, format, handles, 85 pitches, offsets, &fb->id, 0); 86 if (err < 0) { 87 kms_framebuffer_free(fb); 88 return NULL; 89 } 90 91 return fb; 92 } 93 94 void kms_framebuffer_free(struct kms_framebuffer *fb) 95 { 96 struct kms_device *device = fb->device; 97 struct drm_mode_destroy_dumb args; 98 int err; 99 100 if (fb->id) { 101 err = drmModeRmFB(device->fd, fb->id); 102 if (err < 0) { 103 /* not much we can do now */ 104 } 105 } 106 107 memset(&args, 0, sizeof(args)); 108 args.handle = fb->handle; 109 110 err = drmIoctl(device->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &args); 111 if (err < 0) { 112 /* not much we can do now */ 113 } 114 115 free(fb); 116 } 117 118 int kms_framebuffer_map(struct kms_framebuffer *fb, void **ptrp) 119 { 120 struct kms_device *device = fb->device; 121 struct drm_mode_map_dumb args; 122 void *ptr; 123 int err; 124 125 if (fb->ptr) { 126 *ptrp = fb->ptr; 127 return 0; 128 } 129 130 memset(&args, 0, sizeof(args)); 131 args.handle = fb->handle; 132 133 err = drmIoctl(device->fd, DRM_IOCTL_MODE_MAP_DUMB, &args); 134 if (err < 0) 135 return -errno; 136 137 ptr = mmap(0, fb->size, PROT_READ | PROT_WRITE, MAP_SHARED, 138 device->fd, args.offset); 139 if (ptr == MAP_FAILED) 140 return -errno; 141 142 *ptrp = fb->ptr = ptr; 143 144 return 0; 145 } 146 147 void kms_framebuffer_unmap(struct kms_framebuffer *fb) 148 { 149 if (fb->ptr) { 150 munmap(fb->ptr, fb->size); 151 fb->ptr = NULL; 152 } 153 } 154