blob: c606ecc9028b1c955ddbb8e7e188e92a50707dd4 [file] [log] [blame]
Iliyan Malchev202a77d2012-06-11 14:41:12 -07001/*
Duy Truong73d36df2013-02-09 20:33:23 -08002 * Copyright (c) 2011-2012, The Linux Foundation. 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.
Duy Truong73d36df2013-02-09 20:33:23 -080013 * * Neither the name of The Linux Foundation nor the names of its
Iliyan Malchev202a77d2012-06-11 14:41:12 -070014 * 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;
Naseer Ahmeda163b732013-02-12 14:53:33 -050046#ifdef USE_GENLOCK
Iliyan Malchev202a77d2012-06-11 14:41:12 -070047 // If the user sets both a read and write lock, higher preference is
48 // given to the write lock.
49 if (lockType & GENLOCK_WRITE_LOCK) {
50 kLockType = GENLOCK_WRLOCK;
51 } else if (lockType & GENLOCK_READ_LOCK) {
52 kLockType = GENLOCK_RDLOCK;
53 } else {
Naseer Ahmeded670142012-06-20 19:37:18 -070054 ALOGE("%s: invalid lockType (lockType = %d)",
55 __FUNCTION__, lockType);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070056 return -1;
57 }
Naseer Ahmeda163b732013-02-12 14:53:33 -050058#endif
Iliyan Malchev202a77d2012-06-11 14:41:12 -070059 return kLockType;
60 }
61
62 /* Internal function to perform the actual lock/unlock operations */
63 genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
Naseer Ahmeded670142012-06-20 19:37:18 -070064 int lockType, int timeout,
65 int flags)
Iliyan Malchev202a77d2012-06-11 14:41:12 -070066 {
Naseer Ahmeda163b732013-02-12 14:53:33 -050067#ifdef USE_GENLOCK
Iliyan Malchev202a77d2012-06-11 14:41:12 -070068 if (private_handle_t::validate(buffer_handle)) {
69 ALOGE("%s: handle is invalid", __FUNCTION__);
70 return GENLOCK_FAILURE;
71 }
72
Naseer Ahmeded670142012-06-20 19:37:18 -070073 private_handle_t *hnd = reinterpret_cast<private_handle_t*>
74 (buffer_handle);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070075 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
76 if (hnd->genlockPrivFd < 0) {
Naseer Ahmeded670142012-06-20 19:37:18 -070077 ALOGE("%s: the lock has not been created,"
78 "or has not been attached", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070079 return GENLOCK_FAILURE;
80 }
81
82 genlock_lock lock;
83 lock.op = lockType;
Naseer Ahmeded670142012-06-20 19:37:18 -070084 lock.flags = flags;
Iliyan Malchev202a77d2012-06-11 14:41:12 -070085 lock.timeout = timeout;
86 lock.fd = hnd->genlockHandle;
87
Naseer Ahmeded670142012-06-20 19:37:18 -070088#ifdef GENLOCK_IOC_DREADLOCK
89 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_DREADLOCK, &lock)) {
90 ALOGE("%s: GENLOCK_IOC_DREADLOCK failed (lockType0x%x,"
91 "err=%s fd=%d)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -070092 lockType, strerror(errno), hnd->fd);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070093 if (ETIMEDOUT == errno)
94 return GENLOCK_TIMEDOUT;
95
96 return GENLOCK_FAILURE;
97 }
Naseer Ahmeded670142012-06-20 19:37:18 -070098#else
99 // depreciated
100 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
101 ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)"
102 ,__FUNCTION__, lockType, strerror(errno), hnd->fd);
103 if (ETIMEDOUT == errno)
104 return GENLOCK_TIMEDOUT;
105
106 return GENLOCK_FAILURE;
107 }
108#endif
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700109 }
Naseer Ahmeda163b732013-02-12 14:53:33 -0500110#endif
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700111 return GENLOCK_NO_ERROR;
112 }
113
114 /* Internal function to close the fd and release the handle */
115 void close_genlock_fd_and_handle(int& fd, int& handle)
116 {
117 if (fd >=0 ) {
118 close(fd);
119 fd = -1;
120 }
121
122 if (handle >= 0) {
123 close(handle);
124 handle = -1;
125 }
126 }
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700127}
128/*
129 * Create a genlock lock. The genlock lock file descriptor and the lock
130 * handle are stored in the buffer_handle.
131 *
132 * @param: handle of the buffer
133 * @return error status.
134 */
135genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
136{
137 genlock_status_t ret = GENLOCK_NO_ERROR;
Naseer Ahmeda163b732013-02-12 14:53:33 -0500138#ifdef USE_GENLOCK
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700139 if (private_handle_t::validate(buffer_handle)) {
140 ALOGE("%s: handle is invalid", __FUNCTION__);
141 return GENLOCK_FAILURE;
142 }
143
144 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700145 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
146 // Open the genlock device
147 int fd = open(GENLOCK_DEVICE, O_RDWR);
148 if (fd < 0) {
149 ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700150 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700151 return GENLOCK_FAILURE;
152 }
153
154 // Create a new lock
155 genlock_lock lock;
156 if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
157 ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700158 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700159 close_genlock_fd_and_handle(fd, lock.fd);
160 ret = GENLOCK_FAILURE;
161 }
162
163 // Export the lock for other processes to be able to use it.
164 if (GENLOCK_FAILURE != ret) {
165 if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
166 ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700167 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700168 close_genlock_fd_and_handle(fd, lock.fd);
169 ret = GENLOCK_FAILURE;
170 }
171 }
172
173 // Store the lock params in the handle.
174 hnd->genlockPrivFd = fd;
175 hnd->genlockHandle = lock.fd;
176 } else {
177 hnd->genlockHandle = 0;
178 }
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700179#endif
180 return ret;
181}
182
183
184/*
185 * Release a genlock lock associated with the handle.
186 *
187 * @param: handle of the buffer
188 * @return error status.
189 */
190genlock_status_t genlock_release_lock(native_handle_t *buffer_handle)
191{
192 genlock_status_t ret = GENLOCK_NO_ERROR;
193#ifdef USE_GENLOCK
194 if (private_handle_t::validate(buffer_handle)) {
195 ALOGE("%s: handle is invalid", __FUNCTION__);
196 return GENLOCK_FAILURE;
197 }
198
199 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
200 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
201 if (hnd->genlockPrivFd < 0) {
202 ALOGE("%s: the lock is invalid", __FUNCTION__);
203 return GENLOCK_FAILURE;
204 }
205
206 // Close the fd and reset the parameters.
207 close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle);
208 }
209#endif
210 return ret;
211}
212
213
214/*
215 * Attach a lock to the buffer handle passed via an IPC.
216 *
217 * @param: handle of the buffer
218 * @return error status.
219 */
220genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
221{
222 genlock_status_t ret = GENLOCK_NO_ERROR;
223#ifdef USE_GENLOCK
224 if (private_handle_t::validate(buffer_handle)) {
225 ALOGE("%s: handle is invalid", __FUNCTION__);
226 return GENLOCK_FAILURE;
227 }
228
229 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
230 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
231 // Open the genlock device
232 int fd = open(GENLOCK_DEVICE, O_RDWR);
233 if (fd < 0) {
234 ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700235 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700236 return GENLOCK_FAILURE;
237 }
238
239 // Attach the local handle to an existing lock
240 genlock_lock lock;
241 lock.fd = hnd->genlockHandle;
242 if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
243 ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700244 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700245 close_genlock_fd_and_handle(fd, lock.fd);
246 ret = GENLOCK_FAILURE;
247 }
248
249 // Store the relavant information in the handle
250 hnd->genlockPrivFd = fd;
251 }
252#endif
253 return ret;
254}
255
256/*
257 * Lock the buffer specified by the buffer handle. The lock held by the buffer
258 * is specified by the lockType. This function will block if a write lock is
259 * requested on the buffer which has previously been locked for a read or write
260 * operation. A buffer can be locked by multiple clients for read. An optional
261 * timeout value can be specified. By default, there is no timeout.
262 *
263 * @param: handle of the buffer
264 * @param: type of lock to be acquired by the buffer.
265 * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
266 * @return error status.
267 */
268genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700269 genlock_lock_type_t lockType,
270 int timeout)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700271{
272 genlock_status_t ret = GENLOCK_NO_ERROR;
273#ifdef USE_GENLOCK
274 // Translate the locktype
275 int kLockType = get_kernel_lock_type(lockType);
276 if (-1 == kLockType) {
277 ALOGE("%s: invalid lockType", __FUNCTION__);
278 return GENLOCK_FAILURE;
279 }
280
281 if (0 == timeout) {
282 ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
283 }
284 // Call the private function to perform the lock operation specified.
Naseer Ahmeded670142012-06-20 19:37:18 -0700285 ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700286#endif
287 return ret;
288}
289
290
291/*
292 * Unlocks a buffer that has previously been locked by the client.
293 *
294 * @param: handle of the buffer to be unlocked.
295 * @return: error status.
Naseer Ahmed29a26812012-06-14 00:56:20 -0700296 */
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700297genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
298{
299 genlock_status_t ret = GENLOCK_NO_ERROR;
300#ifdef USE_GENLOCK
301 // Do the unlock operation by setting the unlock flag. Timeout is always
302 // 0 in this case.
Naseer Ahmeded670142012-06-20 19:37:18 -0700303 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700304#endif
305 return ret;
306}
307
308/*
309 * Blocks the calling process until the lock held on the handle is unlocked.
310 *
311 * @param: handle of the buffer
312 * @param: timeout value for the wait.
313 * return: error status.
314 */
315genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) {
316#ifdef USE_GENLOCK
317 if (private_handle_t::validate(buffer_handle)) {
318 ALOGE("%s: handle is invalid", __FUNCTION__);
319 return GENLOCK_FAILURE;
320 }
321
322 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
323 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
324 if (hnd->genlockPrivFd < 0) {
325 ALOGE("%s: the lock is invalid", __FUNCTION__);
326 return GENLOCK_FAILURE;
327 }
328
329 if (0 == timeout)
330 ALOGW("%s: timeout = 0", __FUNCTION__);
331
332 genlock_lock lock;
333 lock.fd = hnd->genlockHandle;
334 lock.timeout = timeout;
335 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_WAIT, &lock)) {
Naseer Ahmeded670142012-06-20 19:37:18 -0700336 ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)", __FUNCTION__,
337 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700338 return GENLOCK_FAILURE;
339 }
340 }
341#endif
342 return GENLOCK_NO_ERROR;
343}
Naseer Ahmeded670142012-06-20 19:37:18 -0700344
345/*
346 * Convert a write lock that we own to a read lock
347 *
348 * @param: handle of the buffer
349 * @param: timeout value for the wait.
350 * return: error status.
351 */
352genlock_status_t genlock_write_to_read(native_handle_t *buffer_handle,
353 int timeout) {
354 genlock_status_t ret = GENLOCK_NO_ERROR;
355#ifdef USE_GENLOCK
356 if (0 == timeout) {
357 ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
358 }
359 // Call the private function to perform the lock operation specified.
360#ifdef GENLOCK_IOC_DREADLOCK
361 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK, timeout,
362 GENLOCK_WRITE_TO_READ);
363#else
364 // depreciated
365 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK,
366 timeout, 0);
367#endif
368#endif
369 return ret;
370}