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 static_cast<int>(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_lock_ycbcr(const gralloc_module_t *mod, buffer_handle_t bhandle,
114		int usage, int x, int y, int w, int h, struct android_ycbcr *ycbcr)
115{
116	struct gralloc_drm_handle_t *handle;
117	struct gralloc_drm_bo_t *bo;
118	void *ptr;
119	int err;
120
121	bo = gralloc_drm_bo_from_handle(bhandle);
122	if (!bo)
123		return -EINVAL;
124	handle = bo->handle;
125
126	switch(handle->format) {
127	case HAL_PIXEL_FORMAT_YCbCr_420_888:
128		break;
129	default:
130		return -EINVAL;
131	}
132
133	err = gralloc_drm_bo_lock(bo, usage, x, y, w, h, &ptr);
134	if (err)
135		return err;
136
137	switch(handle->format) {
138	case HAL_PIXEL_FORMAT_YCbCr_420_888:
139		ycbcr->y = ptr;
140		ycbcr->cb = (uint8_t *)ptr + handle->stride * handle->height;
141		ycbcr->cr = (uint8_t *)ycbcr->cb + 1;
142		ycbcr->ystride = handle->stride;
143		ycbcr->cstride = handle->stride;
144		ycbcr->chroma_step = 2;
145		break;
146	default:
147		break;
148	}
149
150	return 0;
151}
152
153static int drm_mod_unlock(const gralloc_module_t *mod, buffer_handle_t handle)
154{
155	struct drm_module_t *dmod = (struct drm_module_t *) mod;
156	struct gralloc_drm_bo_t *bo;
157
158	bo = gralloc_drm_bo_from_handle(handle);
159	if (!bo)
160		return -EINVAL;
161
162	gralloc_drm_bo_unlock(bo);
163
164	return 0;
165}
166
167static int drm_mod_close_gpu0(struct hw_device_t *dev)
168{
169	struct drm_module_t *dmod = (struct drm_module_t *)dev->module;
170	struct alloc_device_t *alloc = (struct alloc_device_t *) dev;
171
172	gralloc_drm_destroy(dmod->drm);
173	delete alloc;
174
175	return 0;
176}
177
178static int drm_mod_free_gpu0(alloc_device_t *dev, buffer_handle_t handle)
179{
180	struct drm_module_t *dmod = (struct drm_module_t *) dev->common.module;
181	struct gralloc_drm_bo_t *bo;
182
183	bo = gralloc_drm_bo_from_handle(handle);
184	if (!bo)
185		return -EINVAL;
186
187	gralloc_drm_bo_decref(bo);
188
189	return 0;
190}
191
192static int drm_mod_alloc_gpu0(alloc_device_t *dev,
193		int w, int h, int format, int usage,
194		buffer_handle_t *handle, int *stride)
195{
196	struct drm_module_t *dmod = (struct drm_module_t *) dev->common.module;
197	struct gralloc_drm_bo_t *bo;
198	int size, bpp, err;
199
200	bpp = gralloc_drm_get_bpp(format);
201	if (!bpp)
202		return -EINVAL;
203
204	bo = gralloc_drm_bo_create(dmod->drm, w, h, format, usage);
205	if (!bo)
206		return -ENOMEM;
207
208	*handle = gralloc_drm_bo_get_handle(bo, stride);
209	/* in pixels */
210	*stride /= bpp;
211
212	return 0;
213}
214
215static int drm_mod_open_gpu0(struct drm_module_t *dmod, hw_device_t **dev)
216{
217	struct alloc_device_t *alloc;
218	int err;
219
220	err = drm_init(dmod);
221	if (err)
222		return err;
223
224	alloc = new alloc_device_t;
225	if (!alloc)
226		return -EINVAL;
227
228	alloc->common.tag = HARDWARE_DEVICE_TAG;
229	alloc->common.version = 0;
230	alloc->common.module = &dmod->base.common;
231	alloc->common.close = drm_mod_close_gpu0;
232
233	alloc->alloc = drm_mod_alloc_gpu0;
234	alloc->free = drm_mod_free_gpu0;
235
236	*dev = &alloc->common;
237
238	return 0;
239}
240
241static int drm_mod_open(const struct hw_module_t *mod,
242		const char *name, struct hw_device_t **dev)
243{
244	struct drm_module_t *dmod = (struct drm_module_t *) mod;
245	int err;
246
247	if (strcmp(name, GRALLOC_HARDWARE_GPU0) == 0)
248		err = drm_mod_open_gpu0(dmod, dev);
249	else
250		err = -EINVAL;
251
252	return err;
253}
254
255static struct hw_module_methods_t drm_mod_methods = {
256	.open = drm_mod_open
257};
258
259struct drm_module_t HAL_MODULE_INFO_SYM = {
260	.base = {
261		.common = {
262			.tag = HARDWARE_MODULE_TAG,
263			.version_major = 1,
264			.version_minor = 0,
265			.id = GRALLOC_HARDWARE_MODULE_ID,
266			.name = "DRM Memory Allocator",
267			.author = "Chia-I Wu",
268			.methods = &drm_mod_methods
269		},
270		.registerBuffer = drm_mod_register_buffer,
271		.unregisterBuffer = drm_mod_unregister_buffer,
272		.lock = drm_mod_lock,
273		.unlock = drm_mod_unlock,
274		.perform = drm_mod_perform,
275		.lock_ycbcr = drm_mod_lock_ycbcr,
276	},
277
278	.mutex = PTHREAD_MUTEX_INITIALIZER,
279	.drm = NULL
280};
281