blob: 150ae13c5f93242c5167b9b2f999100c1b2fb963 [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
41#ifndef USE_GENLOCK
42#define USE_GENLOCK
43#endif
44
45namespace {
Naseer Ahmed29a26812012-06-14 00:56:20 -070046/* Internal function to map the userspace locks to the kernel lock types */
Iliyan Malchev202a77d2012-06-11 14:41:12 -070047 int get_kernel_lock_type(genlock_lock_type lockType)
48 {
49 int kLockType = 0;
50 // If the user sets both a read and write lock, higher preference is
51 // given to the write lock.
52 if (lockType & GENLOCK_WRITE_LOCK) {
53 kLockType = GENLOCK_WRLOCK;
54 } else if (lockType & GENLOCK_READ_LOCK) {
55 kLockType = GENLOCK_RDLOCK;
56 } else {
Naseer Ahmeded670142012-06-20 19:37:18 -070057 ALOGE("%s: invalid lockType (lockType = %d)",
58 __FUNCTION__, lockType);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070059 return -1;
60 }
61 return kLockType;
62 }
63
64 /* Internal function to perform the actual lock/unlock operations */
65 genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
Naseer Ahmeded670142012-06-20 19:37:18 -070066 int lockType, int timeout,
67 int flags)
Iliyan Malchev202a77d2012-06-11 14:41:12 -070068 {
69 if (private_handle_t::validate(buffer_handle)) {
70 ALOGE("%s: handle is invalid", __FUNCTION__);
71 return GENLOCK_FAILURE;
72 }
73
Naseer Ahmeded670142012-06-20 19:37:18 -070074 private_handle_t *hnd = reinterpret_cast<private_handle_t*>
75 (buffer_handle);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070076 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
77 if (hnd->genlockPrivFd < 0) {
Naseer Ahmeded670142012-06-20 19:37:18 -070078 ALOGE("%s: the lock has not been created,"
79 "or has not been attached", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070080 return GENLOCK_FAILURE;
81 }
82
83 genlock_lock lock;
84 lock.op = lockType;
Naseer Ahmeded670142012-06-20 19:37:18 -070085 lock.flags = flags;
Iliyan Malchev202a77d2012-06-11 14:41:12 -070086 lock.timeout = timeout;
87 lock.fd = hnd->genlockHandle;
88
Naseer Ahmeded670142012-06-20 19:37:18 -070089#ifdef GENLOCK_IOC_DREADLOCK
90 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_DREADLOCK, &lock)) {
91 ALOGE("%s: GENLOCK_IOC_DREADLOCK failed (lockType0x%x,"
92 "err=%s fd=%d)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -070093 lockType, strerror(errno), hnd->fd);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070094 if (ETIMEDOUT == errno)
95 return GENLOCK_TIMEDOUT;
96
97 return GENLOCK_FAILURE;
98 }
Naseer Ahmeded670142012-06-20 19:37:18 -070099#else
100 // depreciated
101 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
102 ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)"
103 ,__FUNCTION__, lockType, strerror(errno), hnd->fd);
104 if (ETIMEDOUT == errno)
105 return GENLOCK_TIMEDOUT;
106
107 return GENLOCK_FAILURE;
108 }
109#endif
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700110 }
111 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 }
127
128}
129/*
130 * Create a genlock lock. The genlock lock file descriptor and the lock
131 * handle are stored in the buffer_handle.
132 *
133 * @param: handle of the buffer
134 * @return error status.
135 */
136genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
137{
138 genlock_status_t ret = GENLOCK_NO_ERROR;
139 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);
145#ifdef USE_GENLOCK
146 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
147 // Open the genlock device
148 int fd = open(GENLOCK_DEVICE, O_RDWR);
149 if (fd < 0) {
150 ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700151 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700152 return GENLOCK_FAILURE;
153 }
154
155 // Create a new lock
156 genlock_lock lock;
157 if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
158 ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700159 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700160 close_genlock_fd_and_handle(fd, lock.fd);
161 ret = GENLOCK_FAILURE;
162 }
163
164 // Export the lock for other processes to be able to use it.
165 if (GENLOCK_FAILURE != ret) {
166 if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
167 ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700168 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700169 close_genlock_fd_and_handle(fd, lock.fd);
170 ret = GENLOCK_FAILURE;
171 }
172 }
173
174 // Store the lock params in the handle.
175 hnd->genlockPrivFd = fd;
176 hnd->genlockHandle = lock.fd;
177 } else {
178 hnd->genlockHandle = 0;
179 }
180#else
181 hnd->genlockHandle = 0;
182#endif
183 return ret;
184}
185
186
187/*
188 * Release a genlock lock associated with the handle.
189 *
190 * @param: handle of the buffer
191 * @return error status.
192 */
193genlock_status_t genlock_release_lock(native_handle_t *buffer_handle)
194{
195 genlock_status_t ret = GENLOCK_NO_ERROR;
196#ifdef USE_GENLOCK
197 if (private_handle_t::validate(buffer_handle)) {
198 ALOGE("%s: handle is invalid", __FUNCTION__);
199 return GENLOCK_FAILURE;
200 }
201
202 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
203 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
204 if (hnd->genlockPrivFd < 0) {
205 ALOGE("%s: the lock is invalid", __FUNCTION__);
206 return GENLOCK_FAILURE;
207 }
208
209 // Close the fd and reset the parameters.
210 close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle);
211 }
212#endif
213 return ret;
214}
215
216
217/*
218 * Attach a lock to the buffer handle passed via an IPC.
219 *
220 * @param: handle of the buffer
221 * @return error status.
222 */
223genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
224{
225 genlock_status_t ret = GENLOCK_NO_ERROR;
226#ifdef USE_GENLOCK
227 if (private_handle_t::validate(buffer_handle)) {
228 ALOGE("%s: handle is invalid", __FUNCTION__);
229 return GENLOCK_FAILURE;
230 }
231
232 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
233 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
234 // Open the genlock device
235 int fd = open(GENLOCK_DEVICE, O_RDWR);
236 if (fd < 0) {
237 ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700238 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700239 return GENLOCK_FAILURE;
240 }
241
242 // Attach the local handle to an existing lock
243 genlock_lock lock;
244 lock.fd = hnd->genlockHandle;
245 if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
246 ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700247 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700248 close_genlock_fd_and_handle(fd, lock.fd);
249 ret = GENLOCK_FAILURE;
250 }
251
252 // Store the relavant information in the handle
253 hnd->genlockPrivFd = fd;
254 }
255#endif
256 return ret;
257}
258
259/*
260 * Lock the buffer specified by the buffer handle. The lock held by the buffer
261 * is specified by the lockType. This function will block if a write lock is
262 * requested on the buffer which has previously been locked for a read or write
263 * operation. A buffer can be locked by multiple clients for read. An optional
264 * timeout value can be specified. By default, there is no timeout.
265 *
266 * @param: handle of the buffer
267 * @param: type of lock to be acquired by the buffer.
268 * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
269 * @return error status.
270 */
271genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700272 genlock_lock_type_t lockType,
273 int timeout)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700274{
275 genlock_status_t ret = GENLOCK_NO_ERROR;
276#ifdef USE_GENLOCK
277 // Translate the locktype
278 int kLockType = get_kernel_lock_type(lockType);
279 if (-1 == kLockType) {
280 ALOGE("%s: invalid lockType", __FUNCTION__);
281 return GENLOCK_FAILURE;
282 }
283
284 if (0 == timeout) {
285 ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
286 }
287 // Call the private function to perform the lock operation specified.
Naseer Ahmeded670142012-06-20 19:37:18 -0700288 ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700289#endif
290 return ret;
291}
292
293
294/*
295 * Unlocks a buffer that has previously been locked by the client.
296 *
297 * @param: handle of the buffer to be unlocked.
298 * @return: error status.
Naseer Ahmed29a26812012-06-14 00:56:20 -0700299 */
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700300genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
301{
302 genlock_status_t ret = GENLOCK_NO_ERROR;
303#ifdef USE_GENLOCK
304 // Do the unlock operation by setting the unlock flag. Timeout is always
305 // 0 in this case.
Naseer Ahmeded670142012-06-20 19:37:18 -0700306 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700307#endif
308 return ret;
309}
310
311/*
312 * Blocks the calling process until the lock held on the handle is unlocked.
313 *
314 * @param: handle of the buffer
315 * @param: timeout value for the wait.
316 * return: error status.
317 */
318genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) {
319#ifdef USE_GENLOCK
320 if (private_handle_t::validate(buffer_handle)) {
321 ALOGE("%s: handle is invalid", __FUNCTION__);
322 return GENLOCK_FAILURE;
323 }
324
325 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
326 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
327 if (hnd->genlockPrivFd < 0) {
328 ALOGE("%s: the lock is invalid", __FUNCTION__);
329 return GENLOCK_FAILURE;
330 }
331
332 if (0 == timeout)
333 ALOGW("%s: timeout = 0", __FUNCTION__);
334
335 genlock_lock lock;
336 lock.fd = hnd->genlockHandle;
337 lock.timeout = timeout;
338 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_WAIT, &lock)) {
Naseer Ahmeded670142012-06-20 19:37:18 -0700339 ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)", __FUNCTION__,
340 strerror(errno));
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700341 return GENLOCK_FAILURE;
342 }
343 }
344#endif
345 return GENLOCK_NO_ERROR;
346}
Naseer Ahmeded670142012-06-20 19:37:18 -0700347
348/*
349 * Convert a write lock that we own to a read lock
350 *
351 * @param: handle of the buffer
352 * @param: timeout value for the wait.
353 * return: error status.
354 */
355genlock_status_t genlock_write_to_read(native_handle_t *buffer_handle,
356 int timeout) {
357 genlock_status_t ret = GENLOCK_NO_ERROR;
358#ifdef USE_GENLOCK
359 if (0 == timeout) {
360 ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
361 }
362 // Call the private function to perform the lock operation specified.
363#ifdef GENLOCK_IOC_DREADLOCK
364 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK, timeout,
365 GENLOCK_WRITE_TO_READ);
366#else
367 // depreciated
368 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK,
369 timeout, 0);
370#endif
371#endif
372 return ret;
373}