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