1/*
2 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3 * Copyright (C) 2010-2011 LunarG Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the 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
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#define LOG_TAG "GRALLOC-MOD"
25
26#include <cutils/log.h>
27#include <stdlib.h>
28#include <stdarg.h>
29#include <pthread.h>
30#include <errno.h>
31
32#include "gralloc_drm.h"
33#include "gralloc_drm_priv.h"
34
35/*
36 * Initialize the DRM device object
37 */
38static int drm_init(struct drm_module_t *dmod)
39{
40	int err = 0;
41
42	pthread_mutex_lock(&dmod->mutex);
43	if (!dmod->drm) {
44		dmod->drm = gralloc_drm_create();
45		if (!dmod->drm)
46			err = -EINVAL;
47	}
48	pthread_mutex_unlock(&dmod->mutex);
49
50	return err;
51}
52
53static int drm_mod_perform(const struct gralloc_module_t *mod, int op, ...)
54{
55	struct drm_module_t *dmod = (struct drm_module_t *) mod;
56	va_list args;
57	int err;
58
59	err = drm_init(dmod);
60	if (err)
61		return err;
62
63	va_start(args, op);
64	switch (op) {
65	case GRALLOC_MODULE_PERFORM_GET_DRM_FD:
66		{
67			int *fd = va_arg(args, int *);
68			*fd = gralloc_drm_get_fd(dmod->drm);
69			err = 0;
70		}
71		break;
72	default:
73		err = -EINVAL;
74		break;
75	}
76	va_end(args);
77
78	return err;
79}
80
81static int drm_mod_register_buffer(const gralloc_module_t *mod,
82		buffer_handle_t handle)
83{
84	struct drm_module_t *dmod = (struct drm_module_t *) mod;
85	int err;
86
87	err = drm_init(dmod);
88	if (err)
89		return err;
90
91	return gralloc_drm_handle_register(handle, dmod->drm);
92}
93
94static int drm_mod_unregister_buffer(const gralloc_module_t *mod,
95		buffer_handle_t handle)
96{
97	return gralloc_drm_handle_unregister(handle);
98}
99
100static int drm_mod_lock(const gralloc_module_t *mod, buffer_handle_t handle,
101		int usage, int x, int y, int w, int h, void **ptr)
102{
103	struct gralloc_drm_bo_t *bo;
104	int err;
105
106	bo = gralloc_drm_bo_from_handle(handle);
107	if (!bo)
108		return -EINVAL;
109
110	return gralloc_drm_bo_lock(bo, usage, x, y, w, h, ptr);
111}
112
113static int drm_mod_unlock(const gralloc_module_t *mod, buffer_handle_t handle)
114{
115	struct drm_module_t *dmod = (struct drm_module_t *) mod;
116	struct gralloc_drm_bo_t *bo;
117
118	bo = gralloc_drm_bo_from_handle(handle);
119	if (!bo)
120		return -EINVAL;
121
122	gralloc_drm_bo_unlock(bo);
123
124	return 0;
125}
126
127static int drm_mod_close_gpu0(struct hw_device_t *dev)
128{
129	struct drm_module_t *dmod = (struct drm_module_t *)dev->module;
130	struct alloc_device_t *alloc = (struct alloc_device_t *) dev;
131
132	gralloc_drm_destroy(dmod->drm);
133	delete alloc;
134
135	return 0;
136}
137
138static int drm_mod_free_gpu0(alloc_device_t *dev, buffer_handle_t handle)
139{
140	struct drm_module_t *dmod = (struct drm_module_t *) dev->common.module;
141	struct gralloc_drm_bo_t *bo;
142
143	bo = gralloc_drm_bo_from_handle(handle);
144	if (!bo)
145		return -EINVAL;
146
147	gralloc_drm_bo_decref(bo);
148
149	return 0;
150}
151
152static int drm_mod_alloc_gpu0(alloc_device_t *dev,
153		int w, int h, int format, int usage,
154		buffer_handle_t *handle, int *stride)
155{
156	struct drm_module_t *dmod = (struct drm_module_t *) dev->common.module;
157	struct gralloc_drm_bo_t *bo;
158	int size, bpp, err;
159
160	bpp = gralloc_drm_get_bpp(format);
161	if (!bpp)
162		return -EINVAL;
163
164	bo = gralloc_drm_bo_create(dmod->drm, w, h, format, usage);
165	if (!bo)
166		return -ENOMEM;
167
168	*handle = gralloc_drm_bo_get_handle(bo, stride);
169	/* in pixels */
170	*stride /= bpp;
171
172	return 0;
173}
174
175static int drm_mod_open_gpu0(struct drm_module_t *dmod, hw_device_t **dev)
176{
177	struct alloc_device_t *alloc;
178	int err;
179
180	err = drm_init(dmod);
181	if (err)
182		return err;
183
184	alloc = new alloc_device_t;
185	if (!alloc)
186		return -EINVAL;
187
188	alloc->common.tag = HARDWARE_DEVICE_TAG;
189	alloc->common.version = 0;
190	alloc->common.module = &dmod->base.common;
191	alloc->common.close = drm_mod_close_gpu0;
192
193	alloc->alloc = drm_mod_alloc_gpu0;
194	alloc->free = drm_mod_free_gpu0;
195
196	*dev = &alloc->common;
197
198	return 0;
199}
200
201static int drm_mod_open(const struct hw_module_t *mod,
202		const char *name, struct hw_device_t **dev)
203{
204	struct drm_module_t *dmod = (struct drm_module_t *) mod;
205	int err;
206
207	if (strcmp(name, GRALLOC_HARDWARE_GPU0) == 0)
208		err = drm_mod_open_gpu0(dmod, dev);
209	else
210		err = -EINVAL;
211
212	return err;
213}
214
215static struct hw_module_methods_t drm_mod_methods = {
216	.open = drm_mod_open
217};
218
219struct drm_module_t HAL_MODULE_INFO_SYM = {
220	.base = {
221		.common = {
222			.tag = HARDWARE_MODULE_TAG,
223			.version_major = 1,
224			.version_minor = 0,
225			.id = GRALLOC_HARDWARE_MODULE_ID,
226			.name = "DRM Memory Allocator",
227			.author = "Chia-I Wu",
228			.methods = &drm_mod_methods
229		},
230		.registerBuffer = drm_mod_register_buffer,
231		.unregisterBuffer = drm_mod_unregister_buffer,
232		.lock = drm_mod_lock,
233		.unlock = drm_mod_unlock,
234		.perform = drm_mod_perform
235	},
236
237	.mutex = PTHREAD_MUTEX_INITIALIZER,
238	.drm = NULL
239};
240