• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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