1bb994653667986757b4c906b8f144737667f7374Dave Airlie/**************************************************************************
2bb994653667986757b4c906b8f144737667f7374Dave Airlie *
3bb994653667986757b4c906b8f144737667f7374Dave Airlie * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
4bb994653667986757b4c906b8f144737667f7374Dave Airlie * All Rights Reserved.
5bb994653667986757b4c906b8f144737667f7374Dave Airlie *
6bb994653667986757b4c906b8f144737667f7374Dave Airlie * Permission is hereby granted, free of charge, to any person obtaining a
7bb994653667986757b4c906b8f144737667f7374Dave Airlie * copy of this software and associated documentation files (the
8bb994653667986757b4c906b8f144737667f7374Dave Airlie * "Software"), to deal in the Software without restriction, including
9bb994653667986757b4c906b8f144737667f7374Dave Airlie * without limitation the rights to use, copy, modify, merge, publish,
10bb994653667986757b4c906b8f144737667f7374Dave Airlie * distribute, sub license, and/or sell copies of the Software, and to
11bb994653667986757b4c906b8f144737667f7374Dave Airlie * permit persons to whom the Software is furnished to do so, subject to
12bb994653667986757b4c906b8f144737667f7374Dave Airlie * the following conditions:
13bb994653667986757b4c906b8f144737667f7374Dave Airlie *
14bb994653667986757b4c906b8f144737667f7374Dave Airlie * The above copyright notice and this permission notice (including the
15bb994653667986757b4c906b8f144737667f7374Dave Airlie * next paragraph) shall be included in all copies or substantial portions
16bb994653667986757b4c906b8f144737667f7374Dave Airlie * of the Software.
17bb994653667986757b4c906b8f144737667f7374Dave Airlie *
18bb994653667986757b4c906b8f144737667f7374Dave Airlie * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19bb994653667986757b4c906b8f144737667f7374Dave Airlie * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20bb994653667986757b4c906b8f144737667f7374Dave Airlie * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21bb994653667986757b4c906b8f144737667f7374Dave Airlie * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22bb994653667986757b4c906b8f144737667f7374Dave Airlie * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23bb994653667986757b4c906b8f144737667f7374Dave Airlie * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24bb994653667986757b4c906b8f144737667f7374Dave Airlie * USE OR OTHER DEALINGS IN THE SOFTWARE.
25bb994653667986757b4c906b8f144737667f7374Dave Airlie *
26bb994653667986757b4c906b8f144737667f7374Dave Airlie **************************************************************************/
27bb994653667986757b4c906b8f144737667f7374Dave Airlie
28bb994653667986757b4c906b8f144737667f7374Dave Airlie
298e93afc9765f1de613c65a76e9a86e17db96e653Emil Velikov#ifdef HAVE_CONFIG_H
308e93afc9765f1de613c65a76e9a86e17db96e653Emil Velikov#include "config.h"
318e93afc9765f1de613c65a76e9a86e17db96e653Emil Velikov#endif
32bb994653667986757b4c906b8f144737667f7374Dave Airlie
33bb994653667986757b4c906b8f144737667f7374Dave Airlie#include <errno.h>
34bb994653667986757b4c906b8f144737667f7374Dave Airlie#include <stdio.h>
35bb994653667986757b4c906b8f144737667f7374Dave Airlie#include <stdlib.h>
36bb994653667986757b4c906b8f144737667f7374Dave Airlie#include <string.h>
37bb994653667986757b4c906b8f144737667f7374Dave Airlie#include "internal.h"
38bb994653667986757b4c906b8f144737667f7374Dave Airlie
39bb994653667986757b4c906b8f144737667f7374Dave Airlie#include <sys/ioctl.h>
40bb994653667986757b4c906b8f144737667f7374Dave Airlie#include "xf86drm.h"
41dadc9eff9fd606335a7b3d5d58065a2e8d629672Emil Velikov#include "libdrm.h"
42bb994653667986757b4c906b8f144737667f7374Dave Airlie
43bb994653667986757b4c906b8f144737667f7374Dave Airliestruct dumb_bo
44bb994653667986757b4c906b8f144737667f7374Dave Airlie{
45bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct kms_bo base;
46bb994653667986757b4c906b8f144737667f7374Dave Airlie	unsigned map_count;
47bb994653667986757b4c906b8f144737667f7374Dave Airlie};
48bb994653667986757b4c906b8f144737667f7374Dave Airlie
49bb994653667986757b4c906b8f144737667f7374Dave Airliestatic int
50bb994653667986757b4c906b8f144737667f7374Dave Airliedumb_get_prop(struct kms_driver *kms, unsigned key, unsigned *out)
51bb994653667986757b4c906b8f144737667f7374Dave Airlie{
52bb994653667986757b4c906b8f144737667f7374Dave Airlie	switch (key) {
53bb994653667986757b4c906b8f144737667f7374Dave Airlie	case KMS_BO_TYPE:
54bb994653667986757b4c906b8f144737667f7374Dave Airlie		*out = KMS_BO_TYPE_SCANOUT_X8R8G8B8 | KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
55bb994653667986757b4c906b8f144737667f7374Dave Airlie		break;
56bb994653667986757b4c906b8f144737667f7374Dave Airlie	default:
57bb994653667986757b4c906b8f144737667f7374Dave Airlie		return -EINVAL;
58bb994653667986757b4c906b8f144737667f7374Dave Airlie	}
59bb994653667986757b4c906b8f144737667f7374Dave Airlie	return 0;
60bb994653667986757b4c906b8f144737667f7374Dave Airlie}
61bb994653667986757b4c906b8f144737667f7374Dave Airlie
62bb994653667986757b4c906b8f144737667f7374Dave Airliestatic int
63bb994653667986757b4c906b8f144737667f7374Dave Airliedumb_destroy(struct kms_driver *kms)
64bb994653667986757b4c906b8f144737667f7374Dave Airlie{
65bb994653667986757b4c906b8f144737667f7374Dave Airlie	free(kms);
66bb994653667986757b4c906b8f144737667f7374Dave Airlie	return 0;
67bb994653667986757b4c906b8f144737667f7374Dave Airlie}
68bb994653667986757b4c906b8f144737667f7374Dave Airlie
69bb994653667986757b4c906b8f144737667f7374Dave Airliestatic int
70bb994653667986757b4c906b8f144737667f7374Dave Airliedumb_bo_create(struct kms_driver *kms,
71bb994653667986757b4c906b8f144737667f7374Dave Airlie		 const unsigned width, const unsigned height,
72bb994653667986757b4c906b8f144737667f7374Dave Airlie		 const enum kms_bo_type type, const unsigned *attr,
73bb994653667986757b4c906b8f144737667f7374Dave Airlie		 struct kms_bo **out)
74bb994653667986757b4c906b8f144737667f7374Dave Airlie{
75bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct drm_mode_create_dumb arg;
76bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct dumb_bo *bo;
77bb994653667986757b4c906b8f144737667f7374Dave Airlie	int i, ret;
78bb994653667986757b4c906b8f144737667f7374Dave Airlie
79bb994653667986757b4c906b8f144737667f7374Dave Airlie	for (i = 0; attr[i]; i += 2) {
80bb994653667986757b4c906b8f144737667f7374Dave Airlie		switch (attr[i]) {
81bb994653667986757b4c906b8f144737667f7374Dave Airlie		case KMS_WIDTH:
82bb994653667986757b4c906b8f144737667f7374Dave Airlie		case KMS_HEIGHT:
83bb994653667986757b4c906b8f144737667f7374Dave Airlie			break;
84bb994653667986757b4c906b8f144737667f7374Dave Airlie		case KMS_BO_TYPE:
85bb994653667986757b4c906b8f144737667f7374Dave Airlie			break;
86bb994653667986757b4c906b8f144737667f7374Dave Airlie		default:
87bb994653667986757b4c906b8f144737667f7374Dave Airlie			return -EINVAL;
88bb994653667986757b4c906b8f144737667f7374Dave Airlie		}
89bb994653667986757b4c906b8f144737667f7374Dave Airlie	}
90bb994653667986757b4c906b8f144737667f7374Dave Airlie
91bb994653667986757b4c906b8f144737667f7374Dave Airlie	bo = calloc(1, sizeof(*bo));
92bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (!bo)
93bb994653667986757b4c906b8f144737667f7374Dave Airlie		return -ENOMEM;
94bb994653667986757b4c906b8f144737667f7374Dave Airlie
95bb994653667986757b4c906b8f144737667f7374Dave Airlie	memset(&arg, 0, sizeof(arg));
96bb994653667986757b4c906b8f144737667f7374Dave Airlie
9761be94018ae9c403517d53f69357719224fa6ff3Chris Wilson	/* All BO_TYPE currently are 32bpp formats */
9861be94018ae9c403517d53f69357719224fa6ff3Chris Wilson	arg.bpp = 32;
99bb994653667986757b4c906b8f144737667f7374Dave Airlie	arg.width = width;
100bb994653667986757b4c906b8f144737667f7374Dave Airlie	arg.height = height;
101bb994653667986757b4c906b8f144737667f7374Dave Airlie
102bb994653667986757b4c906b8f144737667f7374Dave Airlie	ret = drmIoctl(kms->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
103bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (ret)
104bb994653667986757b4c906b8f144737667f7374Dave Airlie		goto err_free;
105bb994653667986757b4c906b8f144737667f7374Dave Airlie
106bb994653667986757b4c906b8f144737667f7374Dave Airlie	bo->base.kms = kms;
107bb994653667986757b4c906b8f144737667f7374Dave Airlie	bo->base.handle = arg.handle;
108bb994653667986757b4c906b8f144737667f7374Dave Airlie	bo->base.size = arg.size;
109bb994653667986757b4c906b8f144737667f7374Dave Airlie	bo->base.pitch = arg.pitch;
110bb994653667986757b4c906b8f144737667f7374Dave Airlie
111bb994653667986757b4c906b8f144737667f7374Dave Airlie	*out = &bo->base;
112bb994653667986757b4c906b8f144737667f7374Dave Airlie
113bb994653667986757b4c906b8f144737667f7374Dave Airlie	return 0;
114bb994653667986757b4c906b8f144737667f7374Dave Airlie
115bb994653667986757b4c906b8f144737667f7374Dave Airlieerr_free:
116bb994653667986757b4c906b8f144737667f7374Dave Airlie	free(bo);
117bb994653667986757b4c906b8f144737667f7374Dave Airlie	return ret;
118bb994653667986757b4c906b8f144737667f7374Dave Airlie}
119bb994653667986757b4c906b8f144737667f7374Dave Airlie
120bb994653667986757b4c906b8f144737667f7374Dave Airliestatic int
121bb994653667986757b4c906b8f144737667f7374Dave Airliedumb_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out)
122bb994653667986757b4c906b8f144737667f7374Dave Airlie{
123bb994653667986757b4c906b8f144737667f7374Dave Airlie	switch (key) {
124bb994653667986757b4c906b8f144737667f7374Dave Airlie	default:
125bb994653667986757b4c906b8f144737667f7374Dave Airlie		return -EINVAL;
126bb994653667986757b4c906b8f144737667f7374Dave Airlie	}
127bb994653667986757b4c906b8f144737667f7374Dave Airlie}
128bb994653667986757b4c906b8f144737667f7374Dave Airlie
129bb994653667986757b4c906b8f144737667f7374Dave Airliestatic int
130bb994653667986757b4c906b8f144737667f7374Dave Airliedumb_bo_map(struct kms_bo *_bo, void **out)
131bb994653667986757b4c906b8f144737667f7374Dave Airlie{
132bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct dumb_bo *bo = (struct dumb_bo *)_bo;
133bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct drm_mode_map_dumb arg;
134bb994653667986757b4c906b8f144737667f7374Dave Airlie	void *map = NULL;
135bb994653667986757b4c906b8f144737667f7374Dave Airlie	int ret;
136bb994653667986757b4c906b8f144737667f7374Dave Airlie
137bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (bo->base.ptr) {
138bb994653667986757b4c906b8f144737667f7374Dave Airlie		bo->map_count++;
139bb994653667986757b4c906b8f144737667f7374Dave Airlie		*out = bo->base.ptr;
140bb994653667986757b4c906b8f144737667f7374Dave Airlie		return 0;
141bb994653667986757b4c906b8f144737667f7374Dave Airlie	}
142bb994653667986757b4c906b8f144737667f7374Dave Airlie
143bb994653667986757b4c906b8f144737667f7374Dave Airlie	memset(&arg, 0, sizeof(arg));
144bb994653667986757b4c906b8f144737667f7374Dave Airlie	arg.handle = bo->base.handle;
145bb994653667986757b4c906b8f144737667f7374Dave Airlie
146bb994653667986757b4c906b8f144737667f7374Dave Airlie	ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
147bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (ret)
148bb994653667986757b4c906b8f144737667f7374Dave Airlie		return ret;
149bb994653667986757b4c906b8f144737667f7374Dave Airlie
150dadc9eff9fd606335a7b3d5d58065a2e8d629672Emil Velikov	map = drm_mmap(0, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, arg.offset);
151bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (map == MAP_FAILED)
152bb994653667986757b4c906b8f144737667f7374Dave Airlie		return -errno;
153bb994653667986757b4c906b8f144737667f7374Dave Airlie
154bb994653667986757b4c906b8f144737667f7374Dave Airlie	bo->base.ptr = map;
155bb994653667986757b4c906b8f144737667f7374Dave Airlie	bo->map_count++;
156bb994653667986757b4c906b8f144737667f7374Dave Airlie	*out = bo->base.ptr;
157bb994653667986757b4c906b8f144737667f7374Dave Airlie
158bb994653667986757b4c906b8f144737667f7374Dave Airlie	return 0;
159bb994653667986757b4c906b8f144737667f7374Dave Airlie}
160bb994653667986757b4c906b8f144737667f7374Dave Airlie
161bb994653667986757b4c906b8f144737667f7374Dave Airliestatic int
162bb994653667986757b4c906b8f144737667f7374Dave Airliedumb_bo_unmap(struct kms_bo *_bo)
163bb994653667986757b4c906b8f144737667f7374Dave Airlie{
164bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct dumb_bo *bo = (struct dumb_bo *)_bo;
165bb994653667986757b4c906b8f144737667f7374Dave Airlie	bo->map_count--;
166bb994653667986757b4c906b8f144737667f7374Dave Airlie	return 0;
167bb994653667986757b4c906b8f144737667f7374Dave Airlie}
168bb994653667986757b4c906b8f144737667f7374Dave Airlie
169bb994653667986757b4c906b8f144737667f7374Dave Airliestatic int
170bb994653667986757b4c906b8f144737667f7374Dave Airliedumb_bo_destroy(struct kms_bo *_bo)
171bb994653667986757b4c906b8f144737667f7374Dave Airlie{
172bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct dumb_bo *bo = (struct dumb_bo *)_bo;
173bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct drm_mode_destroy_dumb arg;
174bb994653667986757b4c906b8f144737667f7374Dave Airlie	int ret;
175bb994653667986757b4c906b8f144737667f7374Dave Airlie
176bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (bo->base.ptr) {
177bb994653667986757b4c906b8f144737667f7374Dave Airlie		/* XXX Sanity check map_count */
178dadc9eff9fd606335a7b3d5d58065a2e8d629672Emil Velikov		drm_munmap(bo->base.ptr, bo->base.size);
179bb994653667986757b4c906b8f144737667f7374Dave Airlie		bo->base.ptr = NULL;
180bb994653667986757b4c906b8f144737667f7374Dave Airlie	}
181bb994653667986757b4c906b8f144737667f7374Dave Airlie
182bb994653667986757b4c906b8f144737667f7374Dave Airlie	memset(&arg, 0, sizeof(arg));
183bb994653667986757b4c906b8f144737667f7374Dave Airlie	arg.handle = bo->base.handle;
184bb994653667986757b4c906b8f144737667f7374Dave Airlie
185bb994653667986757b4c906b8f144737667f7374Dave Airlie	ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
186bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (ret)
187bb994653667986757b4c906b8f144737667f7374Dave Airlie		return -errno;
188bb994653667986757b4c906b8f144737667f7374Dave Airlie
189bb994653667986757b4c906b8f144737667f7374Dave Airlie	free(bo);
190bb994653667986757b4c906b8f144737667f7374Dave Airlie	return 0;
191bb994653667986757b4c906b8f144737667f7374Dave Airlie}
192bb994653667986757b4c906b8f144737667f7374Dave Airlie
193bb994653667986757b4c906b8f144737667f7374Dave Airlieint
194bb994653667986757b4c906b8f144737667f7374Dave Airliedumb_create(int fd, struct kms_driver **out)
195bb994653667986757b4c906b8f144737667f7374Dave Airlie{
196bb994653667986757b4c906b8f144737667f7374Dave Airlie	struct kms_driver *kms;
197bb994653667986757b4c906b8f144737667f7374Dave Airlie	int ret;
198bb994653667986757b4c906b8f144737667f7374Dave Airlie	uint64_t cap = 0;
199bb994653667986757b4c906b8f144737667f7374Dave Airlie
200bb994653667986757b4c906b8f144737667f7374Dave Airlie	ret = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &cap);
201bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (ret || cap == 0)
202bb994653667986757b4c906b8f144737667f7374Dave Airlie		return -EINVAL;
203bb994653667986757b4c906b8f144737667f7374Dave Airlie
204bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms = calloc(1, sizeof(*kms));
205bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (!kms)
206bb994653667986757b4c906b8f144737667f7374Dave Airlie		return -ENOMEM;
207bb994653667986757b4c906b8f144737667f7374Dave Airlie
208bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms->fd = fd;
209bb994653667986757b4c906b8f144737667f7374Dave Airlie
210bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms->bo_create = dumb_bo_create;
211bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms->bo_map = dumb_bo_map;
212bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms->bo_unmap = dumb_bo_unmap;
213bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms->bo_get_prop = dumb_bo_get_prop;
214bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms->bo_destroy = dumb_bo_destroy;
215bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms->get_prop = dumb_get_prop;
216bb994653667986757b4c906b8f144737667f7374Dave Airlie	kms->destroy = dumb_destroy;
217bb994653667986757b4c906b8f144737667f7374Dave Airlie	*out = kms;
218bb994653667986757b4c906b8f144737667f7374Dave Airlie
219bb994653667986757b4c906b8f144737667f7374Dave Airlie	return 0;
220bb994653667986757b4c906b8f144737667f7374Dave Airlie}
221