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 
kms_framebuffer_create(struct kms_device * device,unsigned int width,unsigned int height,uint32_t format)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 
kms_framebuffer_free(struct kms_framebuffer * fb)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 
kms_framebuffer_map(struct kms_framebuffer * fb,void ** ptrp)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 
kms_framebuffer_unmap(struct kms_framebuffer * fb)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