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