1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * Copyright@ Samsung Electronics Co. LTD
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*!
19 * \file      exynos_rotator.c
20 * \brief     source file for exynos_rotator HAL
21 * \author    Sunmi Lee (carrotsm.lee@samsung.com)
22 * \date      2012/03/05
23 *
24 * <b>Revision History: </b>
25 * - 2012/03/05 : Sunmi Lee (carrotsm.lee@samsung.com) \n
26 *   Create
27 *
28 */
29
30//#define LOG_NDEBUG 0
31#define LOG_TAG "libexynosrotator"
32#include <cutils/log.h>
33
34#include <sys/types.h>
35#include <sys/ioctl.h>
36#include <videodev2.h>
37#include <fcntl.h>
38#include <stdbool.h>
39#include <string.h>
40#include <unistd.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <time.h>
44
45#include "exynos_rotator.h"
46
47#include "exynos_format.h"
48#include "ExynosMutex.h"
49#include "exynos_v4l2.h"
50
51#define NUM_OF_ROTATOR_PLANES           (3)
52#define NODE_NUM_ROTATOR                (21)
53#define PFX_NODE_ROTATOR                "/dev/video"
54
55#define ROTATOR_MIN_W_SIZE (8)
56#define ROTATOR_MIN_H_SIZE (8)
57
58#define MAX_ROTATOR_WAITING_TIME_FOR_TRYLOCK (16000) // 16msec
59#define ROTATOR_WAITING_TIME_FOR_TRYLOCK      (8000) //  8msec
60
61struct rotator_info {
62    unsigned int       width;
63    unsigned int       height;
64    unsigned int       crop_left;
65    unsigned int       crop_top;
66    unsigned int       crop_width;
67    unsigned int       crop_height;
68    unsigned int       v4l2_colorformat;
69    unsigned int       cacheable;
70
71    int                rotation;
72
73    void              *addr[NUM_OF_ROTATOR_PLANES];
74    bool               stream_on;
75
76    enum v4l2_buf_type buf_type;
77    struct v4l2_format format;
78    struct v4l2_buffer buffer;
79    struct v4l2_plane  planes[NUM_OF_ROTATOR_PLANES];
80    struct v4l2_crop   crop;
81};
82
83struct ROTATOR_HANDLE {
84    int              rotator_fd;
85    struct rotator_info  src;
86    struct rotator_info  dst;
87    void                *op_mutex;
88    void                *obj_mutex;
89    void                *cur_obj_mutex;
90};
91
92static unsigned int m_rotator_get_plane_count(
93    int v4l_pixel_format)
94{
95    int plane_count = 0;
96
97    switch (v4l_pixel_format) {
98    case V4L2_PIX_FMT_RGB32:
99    case V4L2_PIX_FMT_BGR32:
100    case V4L2_PIX_FMT_RGB24:
101    case V4L2_PIX_FMT_RGB565:
102    case V4L2_PIX_FMT_RGB555X:
103    case V4L2_PIX_FMT_RGB444:
104        plane_count = 1;
105        break;
106    case V4L2_PIX_FMT_NV12M:
107    case V4L2_PIX_FMT_NV12MT_16X16:
108    case V4L2_PIX_FMT_NV21:
109    case V4L2_PIX_FMT_NV16:
110    case V4L2_PIX_FMT_NV61:
111        plane_count = 2;
112        break;
113    case V4L2_PIX_FMT_YVU420M:
114    case V4L2_PIX_FMT_YUV422P:
115    case V4L2_PIX_FMT_YUYV:
116    case V4L2_PIX_FMT_UYVY:
117        plane_count = 3;
118        break;
119    default:
120        ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)",
121             __func__, v4l_pixel_format);
122        plane_count = -1;
123        break;
124    }
125
126    return plane_count;
127}
128
129static unsigned int m_rotator_get_plane_size(
130    unsigned int *plane_size,
131    unsigned int  width,
132    unsigned int  height,
133    int           v4l_pixel_format)
134{
135    switch (v4l_pixel_format) {
136    case V4L2_PIX_FMT_RGB32:
137    case V4L2_PIX_FMT_BGR32:
138        plane_size[0] = width * height * 4;
139        break;
140    case V4L2_PIX_FMT_RGB24:
141        plane_size[0] = width * height * 3;
142        break;
143    case V4L2_PIX_FMT_RGB565:
144    case V4L2_PIX_FMT_RGB555X:
145    case V4L2_PIX_FMT_RGB444:
146        plane_size[0] = width * height * 2;
147        break;
148    case V4L2_PIX_FMT_NV12M:
149    case V4L2_PIX_FMT_NV21:
150    case V4L2_PIX_FMT_NV16:
151    case V4L2_PIX_FMT_NV61:
152        plane_size[0] = width * height;
153        plane_size[1] = width * (height / 2);
154        break;
155    case V4L2_PIX_FMT_NV12MT_16X16:
156        plane_size[0] = ALIGN(width, 16) * ALIGN(height, 16);
157        plane_size[1] = ALIGN(width, 16) * ALIGN(height / 2, 8);
158        break;
159    case V4L2_PIX_FMT_YVU420M:
160    case V4L2_PIX_FMT_YUV422P:
161    case V4L2_PIX_FMT_YUYV:
162    case V4L2_PIX_FMT_UYVY:
163        plane_size[0] = width * height;
164        plane_size[1] = (width / 2) * (height / 2);
165        plane_size[2] = (width / 2) * (height / 2);
166        break;
167    default:
168        ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)",
169             __func__, v4l_pixel_format);
170        return -1;
171        break;
172    }
173
174    return 0;
175}
176
177static int m_exynos_rotator_multiple_of_n(
178    int number, int N)
179{
180    int result = number;
181    switch (N) {
182    case 1:
183    case 2:
184    case 4:
185    case 8:
186    case 16:
187    case 32:
188    case 64:
189    case 128:
190    case 256:
191        result = (number - (number & (N-1)));
192        break;
193    default:
194        result = number - (number % N);
195        break;
196    }
197    return result;
198}
199
200static bool m_exynos_rotator_check_src_size(
201    unsigned int *w,      unsigned int *h,
202    unsigned int *crop_x, unsigned int *crop_y,
203    unsigned int *crop_w, unsigned int *crop_h,
204    int v4l2_colorformat)
205{
206    if (*w < ROTATOR_MIN_W_SIZE || *h < ROTATOR_MIN_H_SIZE) {
207        ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
208            __func__, ROTATOR_MIN_W_SIZE, *w, ROTATOR_MIN_H_SIZE, *h);
209        return false;
210    }
211
212    if (*crop_w < ROTATOR_MIN_W_SIZE || *crop_h < ROTATOR_MIN_H_SIZE) {
213        ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
214            __func__, ROTATOR_MIN_W_SIZE,* crop_w, ROTATOR_MIN_H_SIZE, *crop_h);
215        return false;
216    }
217
218    switch (v4l2_colorformat) {
219    // YUV420 3p
220    case V4L2_PIX_FMT_YUV420M:
221    case V4L2_PIX_FMT_YVU420M:
222        *w = ALIGN(*w, 16);
223        *h = ALIGN(*h, 16);
224        break;
225    // YUV420 2p
226    case V4L2_PIX_FMT_NV12M:
227    case V4L2_PIX_FMT_NV12MT:
228    case V4L2_PIX_FMT_NV21M:
229        *w = ALIGN(*w, 8);
230        *h = ALIGN(*h, 8);
231        break;
232    // YUV422
233    case V4L2_PIX_FMT_YUYV:
234    case V4L2_PIX_FMT_YUV422P:
235    case V4L2_PIX_FMT_UYVY:
236    case V4L2_PIX_FMT_NV21:
237    case V4L2_PIX_FMT_NV16:
238    case V4L2_PIX_FMT_YVYU:
239    case V4L2_PIX_FMT_VYUY:
240    // RGB
241    case V4L2_PIX_FMT_RGB32:
242    case V4L2_PIX_FMT_RGB24:
243    case V4L2_PIX_FMT_RGB565:
244    case V4L2_PIX_FMT_BGR32:
245    case V4L2_PIX_FMT_RGB555X:
246    case V4L2_PIX_FMT_RGB444:
247    default:
248        *w = ALIGN(*w, 4);
249        *h = ALIGN(*h, 4);
250        break;
251    }
252    *crop_w = m_exynos_rotator_multiple_of_n(*crop_w, 4);
253    *crop_h = m_exynos_rotator_multiple_of_n(*crop_h, 4);
254
255    return true;
256}
257
258static bool m_exynos_rotator_check_dst_size(
259    unsigned int *w,      unsigned int *h,
260    unsigned int *crop_x, unsigned int *crop_y,
261    unsigned int *crop_w, unsigned int *crop_h,
262    int v4l2_colorformat,
263    int rotation)
264{
265    unsigned int *new_w;
266    unsigned int *new_h;
267    unsigned int *new_crop_w;
268    unsigned int *new_crop_h;
269
270    if (rotation == 90 || rotation == 270) {
271        new_w = h;
272        new_h = w;
273        new_crop_w = crop_h;
274        new_crop_h = crop_w;
275    } else {
276        new_w = w;
277        new_h = h;
278        new_crop_w = crop_w;
279        new_crop_h = crop_h;
280    }
281
282    if (*w < ROTATOR_MIN_W_SIZE || *h < ROTATOR_MIN_H_SIZE) {
283        ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
284            __func__, ROTATOR_MIN_W_SIZE, *w, ROTATOR_MIN_H_SIZE, *h);
285        return false;
286    }
287
288    if (*crop_w < ROTATOR_MIN_W_SIZE || *crop_h < ROTATOR_MIN_H_SIZE) {
289        ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
290            __func__, ROTATOR_MIN_W_SIZE,* crop_w, ROTATOR_MIN_H_SIZE, *crop_h);
291        return false;
292    }
293
294    switch (v4l2_colorformat) {
295    // YUV420 3p
296    case V4L2_PIX_FMT_YUV420M:
297    case V4L2_PIX_FMT_YVU420M:
298        *new_w = ALIGN(*new_w, 16);
299        *new_h = ALIGN(*new_h, 16);
300        break;
301    // YUV420 2p
302    case V4L2_PIX_FMT_NV12M:
303    case V4L2_PIX_FMT_NV12MT:
304    case V4L2_PIX_FMT_NV21M:
305        *new_w = ALIGN(*new_w, 8);
306        *new_h = ALIGN(*new_h, 8);
307        break;
308    // YUV422
309    case V4L2_PIX_FMT_YUYV:
310    case V4L2_PIX_FMT_YUV422P:
311    case V4L2_PIX_FMT_UYVY:
312    case V4L2_PIX_FMT_NV21:
313    case V4L2_PIX_FMT_NV16:
314    case V4L2_PIX_FMT_YVYU:
315    case V4L2_PIX_FMT_VYUY:
316    // RGB
317    case V4L2_PIX_FMT_RGB32:
318    case V4L2_PIX_FMT_RGB24:
319    case V4L2_PIX_FMT_RGB565:
320    case V4L2_PIX_FMT_BGR32:
321    case V4L2_PIX_FMT_RGB555X:
322    case V4L2_PIX_FMT_RGB444:
323    default:
324        *new_w = ALIGN(*new_w, 4);
325        *new_h = ALIGN(*new_h, 4);
326        break;
327    }
328    *new_crop_w = m_exynos_rotator_multiple_of_n(*new_crop_w, 4);
329    *new_crop_h = m_exynos_rotator_multiple_of_n(*new_crop_h, 4);
330
331    return true;
332}
333
334static int m_exynos_rotator_create(void)
335{
336    int          fd = 0;
337    unsigned int cap;
338    char         node[32];
339
340    sprintf(node, "%s%d", PFX_NODE_ROTATOR, NODE_NUM_ROTATOR);
341    fd = exynos_v4l2_open(node, O_RDWR);
342    if (fd < 0) {
343        ALOGE("%s::exynos_v4l2_open(%s) fail", __func__, node);
344        return -1;
345    }
346
347    cap = V4L2_CAP_STREAMING |
348          V4L2_CAP_VIDEO_OUTPUT_MPLANE |
349          V4L2_CAP_VIDEO_CAPTURE_MPLANE;
350
351    if (exynos_v4l2_querycap(fd, cap) == false) {
352        ALOGE("%s::exynos_v4l2_querycap() fail", __func__);
353        if (0 < fd)
354            close(fd);
355        fd = 0;
356        return -1;
357    }
358    return fd;
359}
360
361static bool m_exynos_rotator_destroy(
362    struct ROTATOR_HANDLE *rotator_handle)
363{
364    if (rotator_handle->src.stream_on == true) {
365        if (exynos_v4l2_streamoff(rotator_handle->rotator_fd, rotator_handle->src.buf_type) < 0)
366            ALOGE("%s::exynos_v4l2_streamoff() fail", __func__);
367
368        rotator_handle->src.stream_on = false;
369    }
370
371    if (rotator_handle->dst.stream_on == true) {
372        if (exynos_v4l2_streamoff(rotator_handle->rotator_fd, rotator_handle->dst.buf_type) < 0)
373            ALOGE("%s::exynos_v4l2_streamoff() fail", __func__);
374
375        rotator_handle->dst.stream_on = false;
376    }
377
378    if (0 < rotator_handle->rotator_fd)
379        close(rotator_handle->rotator_fd);
380    rotator_handle->rotator_fd = 0;
381
382    return true;
383}
384
385bool m_exynos_rotator_find_and_trylock_and_create(
386    struct ROTATOR_HANDLE *rotator_handle)
387{
388    int          i                 = 0;
389    bool         flag_find_new_rotator = false;
390    unsigned int total_sleep_time  = 0;
391
392    do {
393        if (exynos_mutex_trylock(rotator_handle->obj_mutex) == true) {
394
395            // destroy old one.
396            m_exynos_rotator_destroy(rotator_handle);
397
398            // create new one.
399            rotator_handle->rotator_fd = m_exynos_rotator_create();
400            if (rotator_handle->rotator_fd < 0) {
401                rotator_handle->rotator_fd = 0;
402                exynos_mutex_unlock(rotator_handle->obj_mutex);
403                continue;
404            }
405
406            if (rotator_handle->cur_obj_mutex)
407                exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
408
409            rotator_handle->cur_obj_mutex = rotator_handle->obj_mutex;
410
411            flag_find_new_rotator = true;
412            break;
413        }
414
415        // waiting for another process doesn't use rotator.
416        // we need to make decision how to do.
417        if (flag_find_new_rotator == false) {
418            usleep(ROTATOR_WAITING_TIME_FOR_TRYLOCK);
419            total_sleep_time += ROTATOR_WAITING_TIME_FOR_TRYLOCK;
420            ALOGV("%s::waiting for anthere process doens't use rotator", __func__);
421        }
422
423    } while(   flag_find_new_rotator == false
424            && total_sleep_time < MAX_ROTATOR_WAITING_TIME_FOR_TRYLOCK);
425
426    if (flag_find_new_rotator == false)
427        ALOGE("%s::we don't have no available rotator.. fail", __func__);
428
429    return flag_find_new_rotator;
430}
431
432static bool m_exynos_rotator_set_format(
433    int                  fd,
434    struct rotator_info *info,
435    bool                 force)
436{
437    struct v4l2_requestbuffers req_buf;
438    int                        plane_count;
439
440    plane_count = m_rotator_get_plane_count(info->v4l2_colorformat);
441    if (plane_count < 0) {
442        ALOGE("%s::not supported v4l2_colorformat", __func__);
443        return false;
444    }
445
446    if (force == false) {
447        // format
448        info->format.type = info->buf_type;
449        if (exynos_v4l2_g_fmt(fd, &info->format) < 0) {
450            ALOGE("%s::exynos_v4l2_g_fmt() fail type=%d", __func__, info->buf_type);
451            return false;
452        }
453
454        if (info->width            != info->format.fmt.pix_mp.width ||
455            info->height           != info->format.fmt.pix_mp.height ||
456            info->v4l2_colorformat != info->format.fmt.pix_mp.pixelformat) {
457            ALOGV("%s::info is different..)", __func__);
458            goto set_hw;
459        }
460
461        // crop
462        if (info->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
463        info->crop.type = info->buf_type;
464        if (exynos_v4l2_g_crop(fd, &info->crop) < 0) {
465            ALOGE("%s::exynos_v4l2_g_crop() fail", __func__);
466            return false;
467        }
468
469        if (info->crop_left   != info->crop.c.left ||
470            info->crop_top    != info->crop.c.top ||
471            info->crop_width  != info->crop.c.width ||
472            info->crop_height != info->crop.c.height) {
473            ALOGV("%s::crop is different..", __func__);
474            goto set_hw;
475        }
476        }
477
478        // rotation value;
479
480        int value = 0;
481
482        if (exynos_v4l2_g_ctrl(fd, V4L2_CID_ROTATE, &value) < 0) {
483            ALOGE("%s::exynos_v4l2_g_ctrl(V4L2_CID_ROTATE) fail");
484            return false;
485        }
486
487        if (info->rotation != value) {
488            ALOGV("%s::rotation is different..", __func__);
489            goto set_hw;
490        }
491
492        // skip s_fmt
493        ALOGV("%s::fmt, crop is same with old-one, so skip s_fmt crop..", __func__);
494        return true;
495    }
496
497set_hw:
498
499    if (info->stream_on == true) {
500        if (exynos_v4l2_streamoff(fd, info->buf_type) < 0) {
501            ALOGE("%s::exynos_v4l2_streamoff() fail", __func__);
502            return false;
503        }
504        info->stream_on = false;
505    }
506
507    if (exynos_v4l2_s_ctrl(fd, V4L2_CID_ROTATE, info->rotation) < 0) {
508        ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_ROTATE) fail", __func__);
509        return false;
510    }
511
512    info->format.fmt.pix_mp.width       = info->width;
513    info->format.fmt.pix_mp.height      = info->height;
514    info->format.fmt.pix_mp.pixelformat = info->v4l2_colorformat;
515    info->format.fmt.pix_mp.field       = V4L2_FIELD_ANY;
516    info->format.fmt.pix_mp.num_planes  = plane_count;
517
518    if (exynos_v4l2_s_fmt(fd, &info->format) < 0) {
519        ALOGE("%s::exynos_v4l2_s_fmt() fail", __func__);
520        return false;
521    }
522
523    if (info->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
524    info->crop.type     = info->buf_type;
525    info->crop.c.left   = info->crop_left;
526    info->crop.c.top    = info->crop_top;
527    info->crop.c.width  = info->crop_width;
528    info->crop.c.height = info->crop_height;
529
530    if (exynos_v4l2_s_crop(fd, &info->crop) < 0) {
531        ALOGE("%s::exynos_v4l2_s_crop() fail", __func__);
532        return false;
533    }
534    }
535
536    if (exynos_v4l2_s_ctrl(fd, V4L2_CID_CACHEABLE, info->cacheable) < 0) {
537        ALOGE("%s::exynos_v4l2_s_ctrl() fail", __func__);
538        return false;
539    }
540
541    req_buf.count  = 1;
542    req_buf.type   = info->buf_type;
543    req_buf.memory = V4L2_MEMORY_USERPTR;
544    if (exynos_v4l2_reqbufs(fd, &req_buf) < 0) {
545        ALOGE("%s::exynos_v4l2_reqbufs() fail", __func__);
546        return false;
547    }
548
549    return true;
550}
551
552static bool m_exynos_rotator_set_addr(
553    int                  fd,
554    struct rotator_info *info)
555{
556    unsigned int i;
557    unsigned int plane_size[NUM_OF_ROTATOR_PLANES];
558
559    m_rotator_get_plane_size(plane_size,
560                         info->width,
561                         info->height,
562                         info->v4l2_colorformat);
563
564    info->buffer.index    = 0;
565    info->buffer.type     = info->buf_type;
566    info->buffer.memory   = V4L2_MEMORY_USERPTR;
567    info->buffer.m.planes = info->planes;
568    info->buffer.length   = info->format.fmt.pix_mp.num_planes;
569
570    for (i = 0; i < info->format.fmt.pix_mp.num_planes; i++) {
571        info->buffer.m.planes[i].m.userptr = (unsigned long)info->addr[i];
572        info->buffer.m.planes[i].length    = plane_size[i];
573        info->buffer.m.planes[i].bytesused = 0;
574    }
575
576    if (exynos_v4l2_qbuf(fd, &info->buffer) < 0) {
577        ALOGE("%s::exynos_v4l2_qbuf() fail", __func__);
578        return false;
579    }
580
581    return true;
582}
583
584void *exynos_rotator_create(void)
585{
586    int i     = 0;
587    int op_id = 0;
588    char mutex_name[32];
589
590    struct ROTATOR_HANDLE *rotator_handle = (struct ROTATOR_HANDLE *)malloc(sizeof(struct ROTATOR_HANDLE));
591    if (rotator_handle == NULL) {
592        ALOGE("%s::malloc(struct ROTATOR_HANDLE) fail", __func__);
593        goto err;
594    }
595
596    rotator_handle->rotator_fd = 0;
597    memset(&rotator_handle->src, 0, sizeof(struct rotator_info));
598    memset(&rotator_handle->dst, 0, sizeof(struct rotator_info));
599
600    rotator_handle->src.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
601    rotator_handle->dst.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
602
603    rotator_handle->op_mutex = NULL;
604    rotator_handle->obj_mutex = NULL;
605    rotator_handle->cur_obj_mutex = NULL;
606
607    srand(time(NULL));
608    op_id = rand() % 1000000; // just make random id
609    sprintf(mutex_name, "%sOp%d", LOG_TAG, op_id);
610    rotator_handle->op_mutex = exynos_mutex_create(EXYNOS_MUTEX_TYPE_PRIVATE, mutex_name);
611    if (rotator_handle->op_mutex == NULL) {
612        ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name);
613        goto err;
614    }
615
616    exynos_mutex_lock(rotator_handle->op_mutex);
617
618    sprintf(mutex_name, "%sObject%d", LOG_TAG, i);
619
620    rotator_handle->obj_mutex = exynos_mutex_create(EXYNOS_MUTEX_TYPE_SHARED, mutex_name);
621    if (rotator_handle->obj_mutex == NULL) {
622        ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name);
623        goto err;
624    }
625
626    if (m_exynos_rotator_find_and_trylock_and_create(rotator_handle) == false) {
627        ALOGE("%s::m_exynos_rotator_find_and_trylock_and_create() fail", __func__);
628        goto err;
629    }
630
631    exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
632    exynos_mutex_unlock(rotator_handle->op_mutex);
633
634    return (void *)rotator_handle;
635
636err:
637    if (rotator_handle) {
638        m_exynos_rotator_destroy(rotator_handle);
639
640        if (rotator_handle->cur_obj_mutex)
641            exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
642
643        if ((rotator_handle->obj_mutex != NULL) &&
644            (exynos_mutex_get_created_status(rotator_handle->obj_mutex) == true)) {
645            if (exynos_mutex_destroy(rotator_handle->obj_mutex) == false)
646                ALOGE("%s::exynos_mutex_destroy() fail", __func__);
647        }
648
649        if (rotator_handle->op_mutex)
650            exynos_mutex_unlock(rotator_handle->op_mutex);
651
652        free(rotator_handle);
653    }
654
655    return NULL;
656}
657
658void exynos_rotator_destroy(
659    void *handle)
660{
661    int i = 0;
662    struct ROTATOR_HANDLE *rotator_handle = (struct ROTATOR_HANDLE *)handle;
663
664    if (handle == NULL) {
665        ALOGE("%s::handle == NULL() fail", __func__);
666        return;
667    }
668
669    exynos_mutex_lock(rotator_handle->op_mutex);
670    exynos_mutex_lock(rotator_handle->cur_obj_mutex);
671
672    m_exynos_rotator_destroy(rotator_handle);
673
674    exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
675
676    if ((rotator_handle->obj_mutex != NULL) &&
677        (exynos_mutex_get_created_status(rotator_handle->obj_mutex) == true)) {
678        if (exynos_mutex_destroy(rotator_handle->obj_mutex) == false)
679            ALOGE("%s::exynos_mutex_destroy() fail", __func__);
680    }
681
682    exynos_mutex_unlock(rotator_handle->op_mutex);
683
684    if (rotator_handle)
685        free(rotator_handle);
686}
687
688int exynos_rotator_set_src_format(
689    void        *handle,
690    unsigned int width,
691    unsigned int height,
692    unsigned int crop_left,
693    unsigned int crop_top,
694    unsigned int crop_width,
695    unsigned int crop_height,
696    unsigned int v4l2_colorformat,
697    unsigned int cacheable)
698{
699    struct ROTATOR_HANDLE *rotator_handle;
700    rotator_handle = (struct ROTATOR_HANDLE *)handle;
701
702    if (handle == NULL) {
703        ALOGE("%s::handle == NULL() fail", __func__);
704        return -1;
705    }
706
707    exynos_mutex_lock(rotator_handle->op_mutex);
708
709    rotator_handle->src.width            = width;
710    rotator_handle->src.height           = height;
711    rotator_handle->src.crop_left        = crop_left;
712    rotator_handle->src.crop_top         = crop_top;
713    rotator_handle->src.crop_width       = crop_width;
714    rotator_handle->src.crop_height      = crop_height;
715    rotator_handle->src.v4l2_colorformat = v4l2_colorformat;
716    rotator_handle->src.cacheable        = cacheable;
717
718    exynos_mutex_unlock(rotator_handle->op_mutex);
719
720    return 0;
721}
722
723int exynos_rotator_set_dst_format(
724    void        *handle,
725    unsigned int width,
726    unsigned int height,
727    unsigned int crop_left,
728    unsigned int crop_top,
729    unsigned int v4l2_colorformat,
730    unsigned int cacheable)
731{
732    struct ROTATOR_HANDLE *rotator_handle;
733    rotator_handle = (struct ROTATOR_HANDLE *)handle;
734
735    if (handle == NULL) {
736        ALOGE("%s::handle == NULL() fail", __func__);
737        return -1;
738    }
739
740    exynos_mutex_lock(rotator_handle->op_mutex);
741
742    rotator_handle->dst.width            = width;
743    rotator_handle->dst.height           = height;
744    rotator_handle->dst.crop_left        = crop_left;
745    rotator_handle->dst.crop_top         = crop_top;
746    rotator_handle->dst.crop_width       = rotator_handle->src.crop_width;
747    rotator_handle->dst.crop_height      = rotator_handle->src.crop_height;
748    rotator_handle->dst.v4l2_colorformat = v4l2_colorformat;
749    rotator_handle->dst.cacheable        = cacheable;
750
751    exynos_mutex_unlock(rotator_handle->op_mutex);
752
753    return 0;
754}
755
756int exynos_rotator_set_rotation(
757    void *handle,
758    int   rotation)
759{
760    int ret = -1;
761    struct ROTATOR_HANDLE *rotator_handle;
762    rotator_handle = (struct ROTATOR_HANDLE *)handle;
763
764    if (handle == NULL) {
765        ALOGE("%s::handle == NULL() fail", __func__);
766        return ret;
767    }
768
769    exynos_mutex_lock(rotator_handle->op_mutex);
770
771    int new_rotation = rotation % 360;
772
773    if (new_rotation % 90 != 0) {
774        ALOGE("%s::rotation(%d) cannot be acceptable fail", __func__, rotation);
775        goto done;
776    }
777
778    if(new_rotation < 0)
779        new_rotation = -new_rotation;
780
781    rotator_handle->src.rotation = new_rotation;
782    rotator_handle->dst.rotation = new_rotation;
783
784    ret = 0;
785done:
786    exynos_mutex_unlock(rotator_handle->op_mutex);
787
788    return ret;
789}
790
791int exynos_rotator_set_src_addr(
792    void *handle,
793    void *addr[3])
794{
795    struct ROTATOR_HANDLE *rotator_handle;
796    rotator_handle = (struct ROTATOR_HANDLE *)handle;
797
798    if (handle == NULL) {
799        ALOGE("%s::handle == NULL() fail", __func__);
800        return -1;
801    }
802
803    exynos_mutex_lock(rotator_handle->op_mutex);
804
805    rotator_handle->src.addr[0] = addr[0];
806    rotator_handle->src.addr[1] = addr[1];
807    rotator_handle->src.addr[2] = addr[2];
808
809    exynos_mutex_unlock(rotator_handle->op_mutex);
810
811    return 0;
812}
813
814int exynos_rotator_set_dst_addr(
815    void *handle,
816    void *addr[3])
817{
818    struct ROTATOR_HANDLE *rotator_handle;
819    rotator_handle = (struct ROTATOR_HANDLE *)handle;
820
821    if (handle == NULL) {
822        ALOGE("%s::handle == NULL() fail", __func__);
823        return -1;
824    }
825
826    exynos_mutex_lock(rotator_handle->op_mutex);
827
828    rotator_handle->dst.addr[0] = addr[0];
829    rotator_handle->dst.addr[1] = addr[1];
830    rotator_handle->dst.addr[2] = addr[2];
831
832    exynos_mutex_unlock(rotator_handle->op_mutex);
833
834    return 0;
835}
836
837int exynos_rotator_convert(
838    void *handle)
839{
840    struct ROTATOR_HANDLE *rotator_handle;
841    int ret    = -1;
842    int i      = 0;
843    rotator_handle = (struct ROTATOR_HANDLE *)handle;
844
845    if (handle == NULL) {
846        ALOGE("%s::handle == NULL() fail", __func__);
847        return -1;
848    }
849
850    char mutex_name[32];
851    bool flag_new_rotator = false;
852
853    exynos_mutex_lock(rotator_handle->op_mutex);
854
855    if (exynos_mutex_trylock(rotator_handle->cur_obj_mutex) == false) {
856        if (m_exynos_rotator_find_and_trylock_and_create(rotator_handle) == false) {
857            ALOGE("%s::m_exynos_rotator_find_and_trylock_and_create() fail", __func__);
858            goto done;
859        }
860        flag_new_rotator = true;
861    }
862
863    if (m_exynos_rotator_check_src_size(&rotator_handle->src.width, &rotator_handle->src.width,
864                                    &rotator_handle->src.crop_left, &rotator_handle->src.crop_top,
865                                    &rotator_handle->src.crop_width, &rotator_handle->src.crop_height,
866                                    rotator_handle->src.v4l2_colorformat) == false) {
867        ALOGE("%s::m_exynos_rotator_check_size(src) fail", __func__);
868        goto done;
869    }
870
871    if (m_exynos_rotator_check_dst_size(&rotator_handle->dst.width, &rotator_handle->dst.height,
872                                    &rotator_handle->dst.crop_left, &rotator_handle->dst.crop_top,
873                                    &rotator_handle->dst.crop_width, &rotator_handle->dst.crop_height,
874                                    rotator_handle->dst.v4l2_colorformat,
875                                    rotator_handle->dst.rotation) == false) {
876        ALOGE("%s::m_exynos_rotator_check_size(dst) fail", __func__);
877        goto done;
878    }
879
880    if (m_exynos_rotator_set_format(rotator_handle->rotator_fd, &rotator_handle->src, flag_new_rotator) == false) {
881        ALOGE("%s::m_exynos_rotator_set_format(src) fail", __func__);
882        goto done;
883    }
884
885    if (m_exynos_rotator_set_format(rotator_handle->rotator_fd, &rotator_handle->dst, flag_new_rotator) == false) {
886        ALOGE("%s::m_exynos_rotator_set_format(dst) fail", __func__);
887        goto done;
888    }
889
890    if (m_exynos_rotator_set_addr(rotator_handle->rotator_fd, &rotator_handle->src) == false) {
891        ALOGE("%s::m_exynos_rotator_set_addr(src) fail", __func__);
892        goto done;
893    }
894
895    if (m_exynos_rotator_set_addr(rotator_handle->rotator_fd, &rotator_handle->dst) == false) {
896        ALOGE("%s::m_exynos_rotator_set_addr(dst) fail", __func__);
897        goto done;
898    }
899
900    if (rotator_handle->src.stream_on == false) {
901        if (exynos_v4l2_streamon(rotator_handle->rotator_fd, rotator_handle->src.buf_type) < 0) {
902            ALOGE("%s::exynos_v4l2_streamon(src) fail", __func__);
903            goto done;
904        }
905        rotator_handle->src.stream_on = true;
906    }
907
908    if (rotator_handle->dst.stream_on == false) {
909        if (exynos_v4l2_streamon(rotator_handle->rotator_fd, rotator_handle->dst.buf_type) < 0) {
910            ALOGE("%s::exynos_v4l2_streamon(dst) fail", __func__);
911            goto done;
912        }
913        rotator_handle->dst.stream_on = true;
914    }
915
916    if (exynos_v4l2_dqbuf(rotator_handle->rotator_fd, &rotator_handle->src.buffer) < 0) {
917        ALOGE("%s::exynos_v4l2_dqbuf(src) fail", __func__);
918        goto done;
919    }
920
921    if (exynos_v4l2_dqbuf(rotator_handle->rotator_fd, &rotator_handle->dst.buffer) < 0) {
922        ALOGE("%s::exynos_v4l2_dqbuf(dst) fail", __func__);
923        goto done;
924    }
925
926    if (rotator_handle->src.stream_on == true) {
927        if (exynos_v4l2_streamoff(rotator_handle->rotator_fd, rotator_handle->src.buf_type) < 0) {
928            ALOGE("%s::exynos_v4l2_streamon(src) fail", __func__);
929            goto done;
930        }
931        rotator_handle->src.stream_on = false;
932    }
933
934    if (rotator_handle->dst.stream_on == true) {
935        if (exynos_v4l2_streamoff(rotator_handle->rotator_fd, rotator_handle->dst.buf_type) < 0) {
936            ALOGE("%s::exynos_v4l2_streamon(dst) fail", __func__);
937            goto done;
938        }
939        rotator_handle->dst.stream_on = false;
940    }
941
942    ret = 0;
943
944done:
945    exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
946    exynos_mutex_unlock(rotator_handle->op_mutex);
947
948    return ret;
949}
950
951int exynos_rotator_connect(
952    void *handle,
953    void *hw)
954{
955    struct ROTATOR_HANDLE *rotator_handle;
956    int ret    = -1;
957    rotator_handle = (struct ROTATOR_HANDLE *)handle;
958
959    if (handle == NULL) {
960        ALOGE("%s::handle == NULL() fail", __func__);
961        return -1;
962    }
963
964    exynos_mutex_lock(rotator_handle->op_mutex);
965
966    if (exynos_mutex_trylock(rotator_handle->cur_obj_mutex) == false) {
967        if (m_exynos_rotator_find_and_trylock_and_create(rotator_handle) == false) {
968            ALOGE("%s::m_exynos_rotator_find_and_trylock_and_create() fail", __func__);
969            goto done;
970        }
971    }
972
973    ret = 0;
974
975done:
976    exynos_mutex_unlock(rotator_handle->op_mutex);
977
978    return ret;
979}
980
981int exynos_rotator_disconnect(
982    void *handle,
983    void *hw)
984{
985    struct ROTATOR_HANDLE *rotator_handle;
986    rotator_handle = (struct ROTATOR_HANDLE *)handle;
987
988    if (handle == NULL) {
989        ALOGE("%s::handle == NULL() fail", __func__);
990        return -1;
991    }
992
993    exynos_mutex_lock(rotator_handle->op_mutex);
994
995    exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
996    exynos_mutex_unlock(rotator_handle->op_mutex);
997
998    return 0;
999}
1000