Home | History | Annotate | Download | only in libgenlock
      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 */
     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 */
     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 */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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