1 /*
2 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
3
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <cutils/log.h>
31 #include <cutils/native_handle.h>
32 #include <gralloc_priv.h>
33 #include <linux/genlock.h>
34 #include <fcntl.h>
35 #include <sys/ioctl.h>
36
37 #include "genlock.h"
38
39 #define GENLOCK_DEVICE "/dev/genlock"
40
41 namespace {
42 /* Internal function to map the userspace locks to the kernel lock types */
get_kernel_lock_type(genlock_lock_type lockType)43 int get_kernel_lock_type(genlock_lock_type lockType)
44 {
45 int kLockType = 0;
46 // If the user sets both a read and write lock, higher preference is
47 // given to the write lock.
48 if (lockType & GENLOCK_WRITE_LOCK) {
49 kLockType = GENLOCK_WRLOCK;
50 } else if (lockType & GENLOCK_READ_LOCK) {
51 kLockType = GENLOCK_RDLOCK;
52 } else {
53 ALOGE("%s: invalid lockType (lockType = %d)",
54 __FUNCTION__, lockType);
55 return -1;
56 }
57 return kLockType;
58 }
59
60 /* Internal function to perform the actual lock/unlock operations */
perform_lock_unlock_operation(native_handle_t * buffer_handle,int lockType,int timeout,int flags)61 genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
62 int lockType, int timeout,
63 int flags)
64 {
65 if (private_handle_t::validate(buffer_handle)) {
66 ALOGE("%s: handle is invalid", __FUNCTION__);
67 return GENLOCK_FAILURE;
68 }
69
70 private_handle_t *hnd = reinterpret_cast<private_handle_t*>
71 (buffer_handle);
72 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
73 if (hnd->genlockPrivFd < 0) {
74 ALOGE("%s: the lock has not been created,"
75 "or has not been attached", __FUNCTION__);
76 return GENLOCK_FAILURE;
77 }
78
79 genlock_lock lock;
80 lock.op = lockType;
81 lock.flags = flags;
82 lock.timeout = timeout;
83 lock.fd = hnd->genlockHandle;
84
85 #ifdef GENLOCK_IOC_DREADLOCK
86 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_DREADLOCK, &lock)) {
87 ALOGE("%s: GENLOCK_IOC_DREADLOCK failed (lockType0x%x,"
88 "err=%s fd=%d)", __FUNCTION__,
89 lockType, strerror(errno), hnd->fd);
90 if (ETIMEDOUT == errno)
91 return GENLOCK_TIMEDOUT;
92
93 return GENLOCK_FAILURE;
94 }
95 #else
96 // depreciated
97 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
98 ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)"
99 ,__FUNCTION__, lockType, strerror(errno), hnd->fd);
100 if (ETIMEDOUT == errno)
101 return GENLOCK_TIMEDOUT;
102
103 return GENLOCK_FAILURE;
104 }
105 #endif
106 }
107 return GENLOCK_NO_ERROR;
108 }
109
110 /* Internal function to close the fd and release the handle */
close_genlock_fd_and_handle(int & fd,int & handle)111 void close_genlock_fd_and_handle(int& fd, int& handle)
112 {
113 if (fd >=0 ) {
114 close(fd);
115 fd = -1;
116 }
117
118 if (handle >= 0) {
119 close(handle);
120 handle = -1;
121 }
122 }
123
124 }
125 /*
126 * Create a genlock lock. The genlock lock file descriptor and the lock
127 * handle are stored in the buffer_handle.
128 *
129 * @param: handle of the buffer
130 * @return error status.
131 */
genlock_create_lock(native_handle_t * buffer_handle)132 genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
133 {
134 genlock_status_t ret = GENLOCK_NO_ERROR;
135 if (private_handle_t::validate(buffer_handle)) {
136 ALOGE("%s: handle is invalid", __FUNCTION__);
137 return GENLOCK_FAILURE;
138 }
139
140 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
141 #ifdef USE_GENLOCK
142 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
143 // Open the genlock device
144 int fd = open(GENLOCK_DEVICE, O_RDWR);
145 if (fd < 0) {
146 ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
147 strerror(errno));
148 return GENLOCK_FAILURE;
149 }
150
151 // Create a new lock
152 genlock_lock lock;
153 if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
154 ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
155 strerror(errno));
156 close_genlock_fd_and_handle(fd, lock.fd);
157 ret = GENLOCK_FAILURE;
158 }
159
160 // Export the lock for other processes to be able to use it.
161 if (GENLOCK_FAILURE != ret) {
162 if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
163 ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
164 strerror(errno));
165 close_genlock_fd_and_handle(fd, lock.fd);
166 ret = GENLOCK_FAILURE;
167 }
168 }
169
170 // Store the lock params in the handle.
171 hnd->genlockPrivFd = fd;
172 hnd->genlockHandle = lock.fd;
173 } else {
174 hnd->genlockHandle = 0;
175 }
176 #else
177 hnd->genlockHandle = 0;
178 #endif
179 return ret;
180 }
181
182
183 /*
184 * Release a genlock lock associated with the handle.
185 *
186 * @param: handle of the buffer
187 * @return error status.
188 */
genlock_release_lock(native_handle_t * buffer_handle)189 genlock_status_t genlock_release_lock(native_handle_t *buffer_handle)
190 {
191 genlock_status_t ret = GENLOCK_NO_ERROR;
192 #ifdef USE_GENLOCK
193 if (private_handle_t::validate(buffer_handle)) {
194 ALOGE("%s: handle is invalid", __FUNCTION__);
195 return GENLOCK_FAILURE;
196 }
197
198 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
199 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
200 if (hnd->genlockPrivFd < 0) {
201 ALOGE("%s: the lock is invalid", __FUNCTION__);
202 return GENLOCK_FAILURE;
203 }
204
205 // Close the fd and reset the parameters.
206 close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle);
207 }
208 #endif
209 return ret;
210 }
211
212
213 /*
214 * Attach a lock to the buffer handle passed via an IPC.
215 *
216 * @param: handle of the buffer
217 * @return error status.
218 */
genlock_attach_lock(native_handle_t * buffer_handle)219 genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
220 {
221 genlock_status_t ret = GENLOCK_NO_ERROR;
222 #ifdef USE_GENLOCK
223 if (private_handle_t::validate(buffer_handle)) {
224 ALOGE("%s: handle is invalid", __FUNCTION__);
225 return GENLOCK_FAILURE;
226 }
227
228 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
229 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
230 // Open the genlock device
231 int fd = open(GENLOCK_DEVICE, O_RDWR);
232 if (fd < 0) {
233 ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
234 strerror(errno));
235 return GENLOCK_FAILURE;
236 }
237
238 // Attach the local handle to an existing lock
239 genlock_lock lock;
240 lock.fd = hnd->genlockHandle;
241 if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
242 ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
243 strerror(errno));
244 close_genlock_fd_and_handle(fd, lock.fd);
245 ret = GENLOCK_FAILURE;
246 }
247
248 // Store the relavant information in the handle
249 hnd->genlockPrivFd = fd;
250 }
251 #endif
252 return ret;
253 }
254
255 /*
256 * Lock the buffer specified by the buffer handle. The lock held by the buffer
257 * is specified by the lockType. This function will block if a write lock is
258 * requested on the buffer which has previously been locked for a read or write
259 * operation. A buffer can be locked by multiple clients for read. An optional
260 * timeout value can be specified. By default, there is no timeout.
261 *
262 * @param: handle of the buffer
263 * @param: type of lock to be acquired by the buffer.
264 * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
265 * @return error status.
266 */
genlock_lock_buffer(native_handle_t * buffer_handle,genlock_lock_type_t lockType,int timeout)267 genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
268 genlock_lock_type_t lockType,
269 int timeout)
270 {
271 genlock_status_t ret = GENLOCK_NO_ERROR;
272 #ifdef USE_GENLOCK
273 // Translate the locktype
274 int kLockType = get_kernel_lock_type(lockType);
275 if (-1 == kLockType) {
276 ALOGE("%s: invalid lockType", __FUNCTION__);
277 return GENLOCK_FAILURE;
278 }
279
280 if (0 == timeout) {
281 ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
282 }
283 // Call the private function to perform the lock operation specified.
284 ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
285 #endif
286 return ret;
287 }
288
289
290 /*
291 * Unlocks a buffer that has previously been locked by the client.
292 *
293 * @param: handle of the buffer to be unlocked.
294 * @return: error status.
295 */
genlock_unlock_buffer(native_handle_t * buffer_handle)296 genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
297 {
298 genlock_status_t ret = GENLOCK_NO_ERROR;
299 #ifdef USE_GENLOCK
300 // Do the unlock operation by setting the unlock flag. Timeout is always
301 // 0 in this case.
302 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
303 #endif
304 return ret;
305 }
306
307 /*
308 * Blocks the calling process until the lock held on the handle is unlocked.
309 *
310 * @param: handle of the buffer
311 * @param: timeout value for the wait.
312 * return: error status.
313 */
genlock_wait(native_handle_t * buffer_handle,int timeout)314 genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) {
315 #ifdef USE_GENLOCK
316 if (private_handle_t::validate(buffer_handle)) {
317 ALOGE("%s: handle is invalid", __FUNCTION__);
318 return GENLOCK_FAILURE;
319 }
320
321 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
322 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
323 if (hnd->genlockPrivFd < 0) {
324 ALOGE("%s: the lock is invalid", __FUNCTION__);
325 return GENLOCK_FAILURE;
326 }
327
328 if (0 == timeout)
329 ALOGW("%s: timeout = 0", __FUNCTION__);
330
331 genlock_lock lock;
332 lock.fd = hnd->genlockHandle;
333 lock.timeout = timeout;
334 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_WAIT, &lock)) {
335 ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)", __FUNCTION__,
336 strerror(errno));
337 return GENLOCK_FAILURE;
338 }
339 }
340 #endif
341 return GENLOCK_NO_ERROR;
342 }
343
344 /*
345 * Convert a write lock that we own to a read lock
346 *
347 * @param: handle of the buffer
348 * @param: timeout value for the wait.
349 * return: error status.
350 */
genlock_write_to_read(native_handle_t * buffer_handle,int timeout)351 genlock_status_t genlock_write_to_read(native_handle_t *buffer_handle,
352 int timeout) {
353 genlock_status_t ret = GENLOCK_NO_ERROR;
354 #ifdef USE_GENLOCK
355 if (0 == timeout) {
356 ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
357 }
358 // Call the private function to perform the lock operation specified.
359 #ifdef GENLOCK_IOC_DREADLOCK
360 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK, timeout,
361 GENLOCK_WRITE_TO_READ);
362 #else
363 // depreciated
364 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK,
365 timeout, 0);
366 #endif
367 #endif
368 return ret;
369 }
370