1/*
2 *  ion.c
3 *
4 * Memory Allocator functions for ion
5 *
6 *   Copyright 2011 Google, Inc
7 *
8 *  Licensed under the Apache License, Version 2.0 (the "License");
9 *  you may not use this file except in compliance with the License.
10 *  You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 *  Unless required by applicable law or agreed to in writing, software
15 *  distributed under the License is distributed on an "AS IS" BASIS,
16 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 *  See the License for the specific language governing permissions and
18 *  limitations under the License.
19 */
20#define LOG_TAG "ion"
21
22#include <cutils/log.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <string.h>
27#include <sys/ioctl.h>
28#include <sys/mman.h>
29#include <sys/types.h>
30
31#include <linux/ion.h>
32#include <ion/ion.h>
33
34int ion_open()
35{
36    int fd = open("/dev/ion", O_RDWR);
37    if (fd < 0)
38        ALOGE("open /dev/ion failed!\n");
39    return fd;
40}
41
42int ion_close(int fd)
43{
44    int ret = close(fd);
45    if (ret < 0)
46        return -errno;
47    return ret;
48}
49
50static int ion_ioctl(int fd, int req, void *arg)
51{
52    int ret = ioctl(fd, req, arg);
53    if (ret < 0) {
54        ALOGE("ioctl %x failed with code %d: %s\n", req,
55              ret, strerror(errno));
56        return -errno;
57    }
58    return ret;
59}
60
61int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask,
62              unsigned int flags, ion_user_handle_t *handle)
63{
64    int ret;
65    struct ion_allocation_data data = {
66        .len = len,
67        .align = align,
68        .heap_id_mask = heap_mask,
69        .flags = flags,
70    };
71
72    if (handle == NULL)
73        return -EINVAL;
74
75    ret = ion_ioctl(fd, ION_IOC_ALLOC, &data);
76    if (ret < 0)
77        return ret;
78    *handle = data.handle;
79    return ret;
80}
81
82int ion_free(int fd, ion_user_handle_t handle)
83{
84    struct ion_handle_data data = {
85        .handle = handle,
86    };
87    return ion_ioctl(fd, ION_IOC_FREE, &data);
88}
89
90int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot,
91            int flags, off_t offset, unsigned char **ptr, int *map_fd)
92{
93    int ret;
94    unsigned char *tmp_ptr;
95    struct ion_fd_data data = {
96        .handle = handle,
97    };
98
99    if (map_fd == NULL)
100        return -EINVAL;
101    if (ptr == NULL)
102        return -EINVAL;
103
104    ret = ion_ioctl(fd, ION_IOC_MAP, &data);
105    if (ret < 0)
106        return ret;
107    if (data.fd < 0) {
108        ALOGE("map ioctl returned negative fd\n");
109        return -EINVAL;
110    }
111    tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
112    if (tmp_ptr == MAP_FAILED) {
113        ALOGE("mmap failed: %s\n", strerror(errno));
114        return -errno;
115    }
116    *map_fd = data.fd;
117    *ptr = tmp_ptr;
118    return ret;
119}
120
121int ion_share(int fd, ion_user_handle_t handle, int *share_fd)
122{
123    int ret;
124    struct ion_fd_data data = {
125        .handle = handle,
126    };
127
128    if (share_fd == NULL)
129        return -EINVAL;
130
131    ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
132    if (ret < 0)
133        return ret;
134    if (data.fd < 0) {
135        ALOGE("share ioctl returned negative fd\n");
136        return -EINVAL;
137    }
138    *share_fd = data.fd;
139    return ret;
140}
141
142int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask,
143                 unsigned int flags, int *handle_fd) {
144    ion_user_handle_t handle;
145    int ret;
146
147    ret = ion_alloc(fd, len, align, heap_mask, flags, &handle);
148    if (ret < 0)
149        return ret;
150    ret = ion_share(fd, handle, handle_fd);
151    ion_free(fd, handle);
152    return ret;
153}
154
155int ion_import(int fd, int share_fd, ion_user_handle_t *handle)
156{
157    int ret;
158    struct ion_fd_data data = {
159        .fd = share_fd,
160    };
161
162    if (handle == NULL)
163        return -EINVAL;
164
165    ret = ion_ioctl(fd, ION_IOC_IMPORT, &data);
166    if (ret < 0)
167        return ret;
168    *handle = data.handle;
169    return ret;
170}
171
172int ion_sync_fd(int fd, int handle_fd)
173{
174    struct ion_fd_data data = {
175        .fd = handle_fd,
176    };
177    return ion_ioctl(fd, ION_IOC_SYNC, &data);
178}
179