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 #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 #ifdef USE_GENLOCK
47 // 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 {
54 ALOGE("%s: invalid lockType (lockType = %d)",
55 __FUNCTION__, lockType);
56 return -1;
57 }
58 #endif
59 return kLockType;
60 }
61
62 /* Internal function to perform the actual lock/unlock operations */
perform_lock_unlock_operation(native_handle_t * buffer_handle,int lockType,int timeout,int flags)63 genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
64 int lockType, int timeout,
65 int flags)
66 {
67 #ifdef USE_GENLOCK
68 if (private_handle_t::validate(buffer_handle)) {
69 ALOGE("%s: handle is invalid", __FUNCTION__);
70 return GENLOCK_FAILURE;
71 }
72
73 private_handle_t *hnd = reinterpret_cast<private_handle_t*>
74 (buffer_handle);
75 if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
76 if (hnd->genlockPrivFd < 0) {
77 ALOGE("%s: the lock has not been created,"
78 "or has not been attached", __FUNCTION__);
79 return GENLOCK_FAILURE;
80 }
81
82 genlock_lock lock;
83 lock.op = lockType;
84 lock.flags = flags;
85 lock.timeout = timeout;
86 lock.fd = hnd->genlockHandle;
87
88 #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__,
92 lockType, strerror(errno), hnd->fd);
93 if (ETIMEDOUT == errno)
94 return GENLOCK_TIMEDOUT;
95
96 return GENLOCK_FAILURE;
97 }
98 #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
109 }
110 #endif
111 return GENLOCK_NO_ERROR;
112 }
113
114 /* Internal function to close the fd and release the handle */
close_genlock_fd_and_handle(int & fd,int & 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 * 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 */
genlock_create_lock(native_handle_t * buffer_handle)135 genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
136 {
137 genlock_status_t ret = GENLOCK_NO_ERROR;
138 #ifdef USE_GENLOCK
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 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__,
150 strerror(errno));
151 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__,
158 strerror(errno));
159 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__,
167 strerror(errno));
168 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 }
179 #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 */
genlock_release_lock(native_handle_t * buffer_handle)190 genlock_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 */
genlock_attach_lock(native_handle_t * buffer_handle)220 genlock_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__,
235 strerror(errno));
236 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__,
244 strerror(errno));
245 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 */
genlock_lock_buffer(native_handle_t * buffer_handle,genlock_lock_type_t lockType,int timeout)268 genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
269 genlock_lock_type_t lockType,
270 int timeout)
271 {
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.
285 ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
286 #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.
296 */
genlock_unlock_buffer(native_handle_t * buffer_handle)297 genlock_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.
303 ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
304 #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 */
genlock_wait(native_handle_t * buffer_handle,int timeout)315 genlock_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)) {
336 ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)", __FUNCTION__,
337 strerror(errno));
338 return GENLOCK_FAILURE;
339 }
340 }
341 #endif
342 return GENLOCK_NO_ERROR;
343 }
344
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 */
genlock_write_to_read(native_handle_t * buffer_handle,int timeout)352 genlock_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 }
371