1 /*
2 * Copyright (c) 2011-2012, The Linux Foundation. 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 The Linux Foundation 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 #ifdef USE_GENLOCK
34 #include <linux/genlock.h>
35 #endif
36 #include <fcntl.h>
37 #include <sys/ioctl.h>
38
39 #include "genlock.h"
40
41 #define GENLOCK_DEVICE "/dev/genlock"
42
43 namespace {
44 /* Internal function to map the userspace locks to the kernel lock types */
get_kernel_lock_type(genlock_lock_type lockType)45 int get_kernel_lock_type(genlock_lock_type lockType)
46 {
47 int kLockType = 0;
48 #ifdef USE_GENLOCK
49 // If the user sets both a read and write lock, higher preference is
50 // given to the write lock.
51 if (lockType & GENLOCK_WRITE_LOCK) {
52 kLockType = GENLOCK_WRLOCK;
53 } else if (lockType & GENLOCK_READ_LOCK) {
54 kLockType = GENLOCK_RDLOCK;
55 } else {
56 ALOGE("%s: invalid lockType (lockType = %d)",
57 __FUNCTION__, lockType);
58 return -1;
59 }
60 #endif
61 return kLockType;
62 }
63
64 /* Internal function to perform the actual lock/unlock operations */
perform_lock_unlock_operation(native_handle_t * buffer_handle,int lockType,int timeout,int flags)65 genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
66 int lockType, int timeout,
67 int flags)
68 {
69 #ifdef USE_GENLOCK
70 if (private_handle_t::validate(buffer_handle)) {
71 ALOGE("%s: handle is invalid", __FUNCTION__);
72 return GENLOCK_FAILURE;
73 }
74
75 private_handle_t *hnd = reinterpret_cast<private_handle_t*>
76 (buffer_handle);
77 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
78 if (hnd->genlockPrivFd < 0) {
79 ALOGE("%s: the lock has not been created,"
80 "or has not been attached", __FUNCTION__);
81 return GENLOCK_FAILURE;
82 }
83
84 genlock_lock lock;
85 lock.op = lockType;
86 lock.flags = flags;
87 lock.timeout = timeout;
88 lock.fd = hnd->genlockHandle;
89
90 #ifdef GENLOCK_IOC_DREADLOCK
91 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_DREADLOCK, &lock)) {
92 ALOGE("%s: GENLOCK_IOC_DREADLOCK failed (lockType0x%x,"
93 "err=%s fd=%d)", __FUNCTION__,
94 lockType, strerror(errno), hnd->fd);
95 if (ETIMEDOUT == errno)
96 return GENLOCK_TIMEDOUT;
97
98 return GENLOCK_FAILURE;
99 }
100 #else
101 // depreciated
102 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
103 ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)"
104 ,__FUNCTION__, lockType, strerror(errno), hnd->fd);
105 if (ETIMEDOUT == errno)
106 return GENLOCK_TIMEDOUT;
107
108 return GENLOCK_FAILURE;
109 }
110 #endif
111 }
112 #endif
113 return GENLOCK_NO_ERROR;
114 }
115
116 /* Internal function to close the fd and release the handle */
close_genlock_fd_and_handle(int & fd,int & handle)117 void close_genlock_fd_and_handle(int& fd, int& handle)
118 {
119 if (fd >=0 ) {
120 close(fd);
121 fd = -1;
122 }
123
124 if (handle >= 0) {
125 close(handle);
126 handle = -1;
127 }
128 }
129 }
130 /*
131 * Create a genlock lock. The genlock lock file descriptor and the lock
132 * handle are stored in the buffer_handle.
133 *
134 * @param: handle of the buffer
135 * @return error status.
136 */
genlock_create_lock(native_handle_t * buffer_handle)137 genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
138 {
139 genlock_status_t ret = GENLOCK_NO_ERROR;
140 #ifdef USE_GENLOCK
141 if (private_handle_t::validate(buffer_handle)) {
142 ALOGE("%s: handle is invalid", __FUNCTION__);
143 return GENLOCK_FAILURE;
144 }
145
146 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
147 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
148 // Open the genlock device
149 int fd = open(GENLOCK_DEVICE, O_RDWR);
150 if (fd < 0) {
151 ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
152 strerror(errno));
153 return GENLOCK_FAILURE;
154 }
155
156 // Create a new lock
157 genlock_lock lock;
158 if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
159 ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
160 strerror(errno));
161 close_genlock_fd_and_handle(fd, lock.fd);
162 ret = GENLOCK_FAILURE;
163 }
164
165 // Export the lock for other processes to be able to use it.
166 if (GENLOCK_FAILURE != ret) {
167 if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
168 ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
169 strerror(errno));
170 close_genlock_fd_and_handle(fd, lock.fd);
171 ret = GENLOCK_FAILURE;
172 }
173 }
174
175 // Store the lock params in the handle.
176 hnd->genlockPrivFd = fd;
177 hnd->genlockHandle = lock.fd;
178 } else {
179 hnd->genlockHandle = 0;
180 }
181 #endif
182 return ret;
183 }
184
185
186 /*
187 * Release a genlock lock associated with the handle.
188 *
189 * @param: handle of the buffer
190 * @return error status.
191 */
genlock_release_lock(native_handle_t * buffer_handle)192 genlock_status_t genlock_release_lock(native_handle_t *buffer_handle)
193 {
194 genlock_status_t ret = GENLOCK_NO_ERROR;
195 #ifdef USE_GENLOCK
196 if (private_handle_t::validate(buffer_handle)) {
197 ALOGE("%s: handle is invalid", __FUNCTION__);
198 return GENLOCK_FAILURE;
199 }
200
201 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
202 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
203 if (hnd->genlockPrivFd < 0) {
204 ALOGE("%s: the lock is invalid", __FUNCTION__);
205 return GENLOCK_FAILURE;
206 }
207
208 // Close the fd and reset the parameters.
209 close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle);
210 }
211 #endif
212 return ret;
213 }
214
215
216 /*
217 * Attach a lock to the buffer handle passed via an IPC.
218 *
219 * @param: handle of the buffer
220 * @return error status.
221 */
genlock_attach_lock(native_handle_t * buffer_handle)222 genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
223 {
224 genlock_status_t ret = GENLOCK_NO_ERROR;
225 #ifdef USE_GENLOCK
226 if (private_handle_t::validate(buffer_handle)) {
227 ALOGE("%s: handle is invalid", __FUNCTION__);
228 return GENLOCK_FAILURE;
229 }
230
231 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
232 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
233 // Open the genlock device
234 int fd = open(GENLOCK_DEVICE, O_RDWR);
235 if (fd < 0) {
236 ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
237 strerror(errno));
238 return GENLOCK_FAILURE;
239 }
240
241 // Attach the local handle to an existing lock
242 genlock_lock lock;
243 lock.fd = hnd->genlockHandle;
244 if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
245 ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
246 strerror(errno));
247 close_genlock_fd_and_handle(fd, lock.fd);
248 ret = GENLOCK_FAILURE;
249 }
250
251 // Store the relavant information in the handle
252 hnd->genlockPrivFd = fd;
253 }
254 #endif
255 return ret;
256 }
257
258 /*
259 * Lock the buffer specified by the buffer handle. The lock held by the buffer
260 * is specified by the lockType. This function will block if a write lock is
261 * requested on the buffer which has previously been locked for a read or write
262 * operation. A buffer can be locked by multiple clients for read. An optional
263 * timeout value can be specified. By default, there is no timeout.
264 *
265 * @param: handle of the buffer
266 * @param: type of lock to be acquired by the buffer.
267 * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
268 * @return error status.
269 */
genlock_lock_buffer(native_handle_t * buffer_handle,genlock_lock_type_t lockType,int timeout)270 genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
271 genlock_lock_type_t lockType,
272 int timeout)
273 {
274 genlock_status_t ret = GENLOCK_NO_ERROR;
275 #ifdef USE_GENLOCK
276 // Translate the locktype
277 int kLockType = get_kernel_lock_type(lockType);
278 if (-1 == kLockType) {
279 ALOGE("%s: invalid lockType", __FUNCTION__);
280 return GENLOCK_FAILURE;
281 }
282
283 if (0 == timeout) {
284 ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
285 }
286 // Call the private function to perform the lock operation specified.
287 ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
288 #endif
289 return ret;
290 }
291
292
293 /*
294 * Unlocks a buffer that has previously been locked by the client.
295 *
296 * @param: handle of the buffer to be unlocked.
297 * @return: error status.
298 */
genlock_unlock_buffer(native_handle_t * buffer_handle)299 genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
300 {
301 genlock_status_t ret = GENLOCK_NO_ERROR;
302 #ifdef USE_GENLOCK
303 // Do the unlock operation by setting the unlock flag. Timeout is always
304 // 0 in this case.
305 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
306 #endif
307 return ret;
308 }
309
310 /*
311 * Blocks the calling process until the lock held on the handle is unlocked.
312 *
313 * @param: handle of the buffer
314 * @param: timeout value for the wait.
315 * return: error status.
316 */
genlock_wait(native_handle_t * buffer_handle,int timeout)317 genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) {
318 #ifdef USE_GENLOCK
319 if (private_handle_t::validate(buffer_handle)) {
320 ALOGE("%s: handle is invalid", __FUNCTION__);
321 return GENLOCK_FAILURE;
322 }
323
324 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
325 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
326 if (hnd->genlockPrivFd < 0) {
327 ALOGE("%s: the lock is invalid", __FUNCTION__);
328 return GENLOCK_FAILURE;
329 }
330
331 if (0 == timeout)
332 ALOGW("%s: timeout = 0", __FUNCTION__);
333
334 genlock_lock lock;
335 lock.fd = hnd->genlockHandle;
336 lock.timeout = timeout;
337 if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_WAIT, &lock)) {
338 ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)", __FUNCTION__,
339 strerror(errno));
340 return GENLOCK_FAILURE;
341 }
342 }
343 #endif
344 return GENLOCK_NO_ERROR;
345 }
346
347 /*
348 * Convert a write lock that we own to a read lock
349 *
350 * @param: handle of the buffer
351 * @param: timeout value for the wait.
352 * return: error status.
353 */
genlock_write_to_read(native_handle_t * buffer_handle,int timeout)354 genlock_status_t genlock_write_to_read(native_handle_t *buffer_handle,
355 int timeout) {
356 genlock_status_t ret = GENLOCK_NO_ERROR;
357 #ifdef USE_GENLOCK
358 if (0 == timeout) {
359 ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
360 }
361 // Call the private function to perform the lock operation specified.
362 #ifdef GENLOCK_IOC_DREADLOCK
363 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK, timeout,
364 GENLOCK_WRITE_TO_READ);
365 #else
366 // depreciated
367 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK,
368 timeout, 0);
369 #endif
370 #endif
371 return ret;
372 }
373