blob: 344cbaae3a9cb2851ecbd42e3352a5e130a063e2 [file] [log] [blame]
Iliyan Malchev202a77d2012-06-11 14:41:12 -07001/*
Naseer Ahmed29a26812012-06-14 00:56:20 -07002 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Iliyan Malchev202a77d2012-06-11 14:41:12 -07003
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
Iliyan Malchev202a77d2012-06-11 14:41:12 -070041namespace {
Naseer Ahmed29a26812012-06-14 00:56:20 -070042/* Internal function to map the userspace locks to the kernel lock types */
Iliyan Malchev202a77d2012-06-11 14:41:12 -070043 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 {
Naseer Ahmeded670142012-06-20 19:37:18 -070053 ALOGE("%s: invalid lockType (lockType = %d)",
54 __FUNCTION__, lockType);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070055 return -1;
56 }
57 return kLockType;
58 }
59
60 /* Internal function to perform the actual lock/unlock operations */
61 genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
Naseer Ahmeded670142012-06-20 19:37:18 -070062 int lockType, int timeout,
63 int flags)
Iliyan Malchev202a77d2012-06-11 14:41:12 -070064 {
65 if (private_handle_t::validate(buffer_handle)) {
66 ALOGE("%s: handle is invalid", __FUNCTION__);
67 return GENLOCK_FAILURE;
68 }
69
Naseer Ahmeded670142012-06-20 19:37:18 -070070 private_handle_t *hnd = reinterpret_cast<private_handle_t*>
71 (buffer_handle);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070072 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
73 if (hnd->genlockPrivFd < 0) {
Naseer Ahmeded670142012-06-20 19:37:18 -070074 ALOGE("%s: the lock has not been created,"
75 "or has not been attached", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070076 return GENLOCK_FAILURE;
77 }
78
79 genlock_lock lock;
80 lock.op = lockType;
Naseer Ahmeded670142012-06-20 19:37:18 -070081 lock.flags = flags;
Iliyan Malchev202a77d2012-06-11 14:41:12 -070082 lock.timeout = timeout;
83 lock.fd = hnd->genlockHandle;
84
Naseer Ahmeded670142012-06-20 19:37:18 -070085#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__,
Naseer Ahmed29a26812012-06-14 00:56:20 -070089 lockType, strerror(errno), hnd->fd);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070090 if (ETIMEDOUT == errno)
91 return GENLOCK_TIMEDOUT;
92
93 return GENLOCK_FAILURE;
94 }
Naseer Ahmeded670142012-06-20 19:37:18 -070095#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
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700106 }
107 return GENLOCK_NO_ERROR;
108 }
109
110 /* Internal function to close the fd and release the 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 */
132genlock_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__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700147 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700148 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__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700155 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700156 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__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700164 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700165 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 */
189genlock_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 */
219genlock_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__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700234 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700235 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__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700243 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700244 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 */
267genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700268 genlock_lock_type_t lockType,
269 int timeout)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700270{
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.
Naseer Ahmeded670142012-06-20 19:37:18 -0700284 ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700285#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.
Naseer Ahmed29a26812012-06-14 00:56:20 -0700295 */
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700296genlock_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.
Naseer Ahmeded670142012-06-20 19:37:18 -0700302 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700303#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 */
314genlock_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)) {
Naseer Ahmeded670142012-06-20 19:37:18 -0700335 ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)", __FUNCTION__,
336 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700337 return GENLOCK_FAILURE;
338 }
339 }
340#endif
341 return GENLOCK_NO_ERROR;
342}
Naseer Ahmeded670142012-06-20 19:37:18 -0700343
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 */
351genlock_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}