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#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <errno.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include "internal.h"
38
39#include <sys/ioctl.h>
40#include "xf86drm.h"
41#include "libdrm_macros.h"
42
43#include "i915_drm.h"
44
45struct intel_bo
46{
47	struct kms_bo base;
48	unsigned map_count;
49};
50
51static int
52intel_get_prop(struct kms_driver *kms, unsigned key, unsigned *out)
53{
54	switch (key) {
55	case KMS_BO_TYPE:
56		*out = KMS_BO_TYPE_SCANOUT_X8R8G8B8 | KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
57		break;
58	default:
59		return -EINVAL;
60	}
61	return 0;
62}
63
64static int
65intel_destroy(struct kms_driver *kms)
66{
67	free(kms);
68	return 0;
69}
70
71static int
72intel_bo_create(struct kms_driver *kms,
73		 const unsigned width, const unsigned height,
74		 const enum kms_bo_type type, const unsigned *attr,
75		 struct kms_bo **out)
76{
77	struct drm_i915_gem_create arg;
78	unsigned size, pitch;
79	struct intel_bo *bo;
80	int i, ret;
81
82	for (i = 0; attr[i]; i += 2) {
83		switch (attr[i]) {
84		case KMS_WIDTH:
85		case KMS_HEIGHT:
86		case KMS_BO_TYPE:
87			break;
88		default:
89			return -EINVAL;
90		}
91	}
92
93	bo = calloc(1, sizeof(*bo));
94	if (!bo)
95		return -ENOMEM;
96
97	if (type == KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8) {
98		pitch = 64 * 4;
99		size = 64 * 64 * 4;
100	} else if (type == KMS_BO_TYPE_SCANOUT_X8R8G8B8) {
101		pitch = width * 4;
102		pitch = (pitch + 512 - 1) & ~(512 - 1);
103		size = pitch * ((height + 4 - 1) & ~(4 - 1));
104	} else {
105		free(bo);
106		return -EINVAL;
107	}
108
109	memset(&arg, 0, sizeof(arg));
110	arg.size = size;
111
112	ret = drmCommandWriteRead(kms->fd, DRM_I915_GEM_CREATE, &arg, sizeof(arg));
113	if (ret)
114		goto err_free;
115
116	bo->base.kms = kms;
117	bo->base.handle = arg.handle;
118	bo->base.size = size;
119	bo->base.pitch = pitch;
120
121	*out = &bo->base;
122	if (type == KMS_BO_TYPE_SCANOUT_X8R8G8B8 && pitch > 512) {
123		struct drm_i915_gem_set_tiling tile;
124
125		memset(&tile, 0, sizeof(tile));
126		tile.handle = bo->base.handle;
127		tile.tiling_mode = I915_TILING_X;
128		tile.stride = bo->base.pitch;
129
130		ret = drmCommandWriteRead(kms->fd, DRM_I915_GEM_SET_TILING, &tile, sizeof(tile));
131#if 0
132		if (ret) {
133			kms_bo_destroy(out);
134			return ret;
135		}
136#endif
137	}
138
139	return 0;
140
141err_free:
142	free(bo);
143	return ret;
144}
145
146static int
147intel_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out)
148{
149	switch (key) {
150	default:
151		return -EINVAL;
152	}
153}
154
155static int
156intel_bo_map(struct kms_bo *_bo, void **out)
157{
158	struct intel_bo *bo = (struct intel_bo *)_bo;
159	struct drm_i915_gem_mmap_gtt arg;
160	void *map = NULL;
161	int ret;
162
163	if (bo->base.ptr) {
164		bo->map_count++;
165		*out = bo->base.ptr;
166		return 0;
167	}
168
169	memset(&arg, 0, sizeof(arg));
170	arg.handle = bo->base.handle;
171
172	ret = drmCommandWriteRead(bo->base.kms->fd, DRM_I915_GEM_MMAP_GTT, &arg, sizeof(arg));
173	if (ret)
174		return ret;
175
176	map = drm_mmap(0, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, arg.offset);
177	if (map == MAP_FAILED)
178		return -errno;
179
180	bo->base.ptr = map;
181	bo->map_count++;
182	*out = bo->base.ptr;
183
184	return 0;
185}
186
187static int
188intel_bo_unmap(struct kms_bo *_bo)
189{
190	struct intel_bo *bo = (struct intel_bo *)_bo;
191	bo->map_count--;
192	return 0;
193}
194
195static int
196intel_bo_destroy(struct kms_bo *_bo)
197{
198	struct intel_bo *bo = (struct intel_bo *)_bo;
199	struct drm_gem_close arg;
200	int ret;
201
202	if (bo->base.ptr) {
203		/* XXX Sanity check map_count */
204		drm_munmap(bo->base.ptr, bo->base.size);
205		bo->base.ptr = NULL;
206	}
207
208	memset(&arg, 0, sizeof(arg));
209	arg.handle = bo->base.handle;
210
211	ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_GEM_CLOSE, &arg);
212	if (ret)
213		return -errno;
214
215	free(bo);
216	return 0;
217}
218
219drm_private int
220intel_create(int fd, struct kms_driver **out)
221{
222	struct kms_driver *kms;
223
224	kms = calloc(1, sizeof(*kms));
225	if (!kms)
226		return -ENOMEM;
227
228	kms->fd = fd;
229
230	kms->bo_create = intel_bo_create;
231	kms->bo_map = intel_bo_map;
232	kms->bo_unmap = intel_bo_unmap;
233	kms->bo_get_prop = intel_bo_get_prop;
234	kms->bo_destroy = intel_bo_destroy;
235	kms->get_prop = intel_get_prop;
236	kms->destroy = intel_destroy;
237	*out = kms;
238
239	return 0;
240}
241