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