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