aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ion.c
blob: 59f7b3b8931084f25cd3fe576164dce28f476e54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <ion/ion.h>
#include <linux/ion_4.12.h>

#include "ion.h"

int ion_get_heap_id(int ion_fd, uint32_t heap_type)
{
	int heap_count = 0;
	int ret = -1;

	if (ion_query_heap_cnt(ion_fd, &heap_count))
	{
		return -1;
	}

	struct ion_heap_data *heap_data =
			malloc(heap_count * sizeof(struct ion_heap_data));

	if (ion_query_get_heaps(ion_fd, heap_count, heap_data))
	{
		free(heap_data);
		return -1;
	}

	for (struct ion_heap_data *hi = heap_data;
	     (hi - heap_data) < heap_count;
	     ++hi)
	{
		if (hi->type == heap_type)
		{
			ret = hi->heap_id;
			break;
		}
	}

	free(heap_data);

	return ret;
}

static const int kBitsInAnInt = (sizeof(int) * 8);

int ion_alloc_one_fd(int ion_fd, size_t size, int heap_id, int *ion_buffer_fd)
{
	if (heap_id < 0 || heap_id >= kBitsInAnInt)
	{
		return -1;
	}

	const int align = 0;
	const int heap_mask = 1 << heap_id;
	const int flags = 0;

	return ion_alloc_fd(ion_fd, size, align, heap_mask, flags, ion_buffer_fd);
}

int ion_mmap(void **ptr, int ion_buffer_fd, size_t size)
{
	void *const k_addr = 0;
	const int k_prot = PROT_READ | PROT_WRITE;
	const int k_flags = MAP_SHARED;

	void *ret = mmap(k_addr, size, k_prot, k_flags, ion_buffer_fd, 0);

	if (ret == MAP_FAILED)
	{
		return -1;
	}

	*ptr = ret;
	return 0;
}

int ion_munmap(void *ptr, size_t size)
{
	if (munmap(ptr, size))
	{
		return -1;
	}

	return 0;
}

int drm_check_prime_caps(int drm_fd)
{
	struct drm_get_cap drm_get_cap_arg = {
		.capability = DRM_CAP_PRIME,
		.value = 0
	};

	if (drmIoctl(drm_fd, DRM_IOCTL_GET_CAP, &drm_get_cap_arg))
	{
		return -1;
	}

	if (!(drm_get_cap_arg.value & DRM_PRIME_CAP_IMPORT) ||
	    !(drm_get_cap_arg.value & DRM_PRIME_CAP_EXPORT))
	{
		return -1;
	}

	return 0;
}

int gem_handle_for_ion_buffer(int drm_fd, uint32_t *gem_handle, int ion_buffer_fd)
{
	struct drm_prime_handle drm_prime_fd_to_handle_arg = {
		.handle = 0,
		.flags = 0,
		.fd = ion_buffer_fd
	};

	if (drmIoctl(drm_fd,
		     DRM_IOCTL_PRIME_FD_TO_HANDLE,
		     &drm_prime_fd_to_handle_arg))
	{
		return -1;
	}

	*gem_handle = drm_prime_fd_to_handle_arg.handle;

	return 0;
}

int ion_fd_for_gem_handle(int drm_fd, int *ion_fd, uint32_t gem_handle)
{
	struct drm_prime_handle drm_prime_handle_to_fd_arg = {
		.handle = gem_handle,
		.flags = 0,
		.fd = 0
	};

	if (drmIoctl(drm_fd,
		     DRM_IOCTL_PRIME_HANDLE_TO_FD,
		     &drm_prime_handle_to_fd_arg))
	{
		return -1;
	}

	*ion_fd = drm_prime_handle_to_fd_arg.fd;

	return 0;
}

int drm_fb_for_ion_buffer(int drm_fd, uint32_t *fb_id, int ion_buffer_fd,
			  const struct fb_configuration *fb_config)
{
	uint32_t gem_handle = 0;

	if (gem_handle_for_ion_buffer(drm_fd, &gem_handle, ion_buffer_fd))
	{
		return -1;
	}

	int ret = drm_fb_for_gem_handle(drm_fd, fb_id, gem_handle, fb_config);

	gem_release_handle(drm_fd, gem_handle);
	return ret;
}

void drm_release_fb(int drm_fd, uint32_t fb_id)
{
	(void)drmIoctl(drm_fd, DRM_IOCTL_MODE_RMFB, &fb_id);
}

int ion_clone_fd_via_gem(int drm_fd, int *cloned_fd, int ion_buffer_fd)
{
	uint32_t gem_handle = 0;
	if (gem_handle_for_ion_buffer(drm_fd, &gem_handle, ion_buffer_fd))
	{
		return -1;
	}

	int ret = ion_fd_for_gem_handle(drm_fd, cloned_fd, gem_handle);
	gem_release_handle(drm_fd, gem_handle);

	return ret;
}