blob: f0809d386a77c28aec7a9e2ff7a8a304218b9e61 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#undef LOG_TAG
#define LOG_TAG "repeater"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <BufferAllocator/BufferAllocator.h>
#include <utils/Log.h>
#include "exynos_format.h"
#include "repeater.h"
#include "repeater_hal.h"
#define REPEATER_DEV_NAME "/dev/repeater"
/* FIX ME */
#define __ALIGN_UP(x,a) (((x) + ((a) - 1)) & ~((a) - 1))
#define NV12N_Y_SIZE(w,h) (__ALIGN_UP((w), 16) * __ALIGN_UP((h), 16) + 256)
#define NV12N_CBCR_SIZE(w,h) (__ALIGN_UP((__ALIGN_UP((w), 16) * (__ALIGN_UP((h), 16) / 2) + 256), 16))
#define v4l2_fourcc(a,b,c,d) ((__u32) (a) | ((__u32) (b) << 8) | ((__u32) (c) << 16) | ((__u32) (d) << 24))
#define V4L2_PIX_FMT_NV12N v4l2_fourcc('N', 'N', '1', '2')
#define ION_EXYNOS_FLAG_PROTECTED (1 << 16)
#define ION_EXYNOS_HEAP_ID_SYSTEM 0
#define ION_EXYNOS_HEAP_ID_VIDEO_FRAME 5
#define ION_FLAG_PROTECTED (16 | ION_EXYNOS_FLAG_PROTECTED)
#define MAX_HEAP_NAME 32
struct repeater_hal {
struct repeater_info info;
int repeater_fd;
void *buf_addr[MAX_SHARED_BUFFER_NUM];
};
struct dma_ion_heap_map {
const char *heap_name;
const char *ion_heap_name;
unsigned int ion_heap_id;
unsigned int ion_heap_flags;
unsigned int legacy_ion_heap_mask;
unsigned int legacy_ion_heap_flags;
} dma_ion_heap_maps[2] = {
{"system-uncached", "ion_system_heap",
ION_EXYNOS_HEAP_ID_SYSTEM, 0,
1 << ION_EXYNOS_HEAP_ID_SYSTEM, 0},
{"system-secure-vframe-secure", "vframe_heap",
ION_EXYNOS_HEAP_ID_VIDEO_FRAME, ION_FLAG_PROTECTED,
1 << ION_EXYNOS_HEAP_ID_VIDEO_FRAME, ION_FLAG_PROTECTED},
};
void *repeater_open()
{
struct repeater_hal *hal;
int i;
hal = (struct repeater_hal *)malloc(sizeof(struct repeater_hal));
hal->repeater_fd = open(REPEATER_DEV_NAME, O_RDWR);
if (hal->repeater_fd < 0)
{
ALOGE("%s: open fail repeater module (%s)", __FUNCTION__, REPEATER_DEV_NAME);
free(hal);
return NULL;
}
for (i = 0; i < MAX_SHARED_BUFFER_NUM; i++)
hal->info.buf_fd[i] = -1;
ALOGI("repeater opened");
return hal;
}
void repeater_close(void *handle)
{
struct repeater_hal *hal;
if (!handle)
return;
hal = (struct repeater_hal *)handle;
if (hal->repeater_fd > 0) {
close(hal->repeater_fd);
hal->repeater_fd = -1;
}
free(hal);
ALOGI("repeater close");
}
int repeater_map(void *handle, struct repeater_map_info *map_info)
{
int ret;
struct repeater_hal *hal;
int i;
int size = 0;
int w = map_info->w;
int h = map_info->h;
int fps = map_info->fps;
bool enable_hdcp = map_info->enable_hdcp;
struct dma_ion_heap_map heap_map = dma_ion_heap_maps[0];
if (!handle)
return -ENOENT;
hal = (struct repeater_hal *)handle;
std::unique_ptr<BufferAllocator> bufallocator(new BufferAllocator());
/* allocated buffer free */
for (i = 0; i < MAX_SHARED_BUFFER_NUM; i++) {
if (hal->info.buf_fd[i] > 0) {
close(hal->info.buf_fd[i]);
hal->info.buf_fd[i] = -1;
}
}
size = NV12N_Y_SIZE(w, h) + NV12N_CBCR_SIZE(w, h);
if (enable_hdcp) {
heap_map = dma_ion_heap_maps[1];
}
ret = bufallocator->MapNameToIonHeap(heap_map.heap_name, heap_map.ion_heap_name,
heap_map.ion_heap_flags, heap_map.legacy_ion_heap_mask, heap_map.legacy_ion_heap_flags);
if (ret < 0) {
ALOGE("failed to dmabufheap MapNameToIonHeap");
return ret;
}
ALOGI("hwfc buffer attribute: heap_name %s heap_id %d, ion_flags 0x%x",
heap_map.heap_name, heap_map.ion_heap_id, heap_map.ion_heap_flags);
ALOGI("repeater_map(), width %d, height %d, NV12N_Y_SIZE() %d, NV12N_CBCR_SIZE() %d",
w, h, NV12N_Y_SIZE(w, h), NV12N_CBCR_SIZE(w, h));
/* buffer alloc */
for (i = 0; i < MAX_SHARED_BUFFER_NUM; i++) {
int fd = bufallocator->Alloc(heap_map.heap_name, size);
if (fd < 0) {
ALOGE("fail to dmabufheap alloc");
hal->info.buf_fd[i] = -1;
return -ENOMEM;
}
hal->info.buf_fd[i] = fd;
hal->buf_addr[i] = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, hal->info.buf_fd[i], 0);
}
hal->info.width = w;
hal->info.height = h;
hal->info.fps = fps;
hal->info.pixel_format = V4L2_PIX_FMT_NV12N;
hal->info.buffer_count = MAX_SHARED_BUFFER_NUM;
ret = ioctl(hal->repeater_fd, REPEATER_IOCTL_MAP_BUF, &hal->info);
if (ret < 0) {
ALOGE("fail to ioctl: REPEATER_IOCTL_MAP_BUF");
return ret;
}
ret = ioctl(hal->repeater_fd, REPEATER_IOCTL_SET_MAX_SKIPPED_FRAME, &map_info->max_skipped_frame);
if (ret < 0) {
ALOGE("fail to ioctl: REPEATER_IOCTL_SET_MAX_SKIPPED_FRAME");
return ret;
}
ALOGI("repeater map success");
return ret;
}
void repeater_unmap(void *handle)
{
struct repeater_hal *hal;
int i;
int width, height;
int size;
if (!handle)
return;
hal = (struct repeater_hal *)handle;
ioctl(hal->repeater_fd, REPEATER_IOCTL_UNMAP_BUF);
/* buffer free */
width = hal->info.width;
height = hal->info.height;
size = NV12N_Y_SIZE(width, height) + NV12N_CBCR_SIZE(width, height);
for (i = 0; i < MAX_SHARED_BUFFER_NUM; i++) {
if (hal->info.buf_fd[i] > 0) {
if (hal->buf_addr[i])
munmap(hal->buf_addr[i], size);
close(hal->info.buf_fd[i]);
hal->info.buf_fd[i] = -1;
}
}
ALOGI("repeater_unmap");
}
int repeater_start(void *handle)
{
int ret;
struct repeater_hal *hal;
if (!handle)
return -ENOENT;
hal = (struct repeater_hal *)handle;
ret = ioctl(hal->repeater_fd, REPEATER_IOCTL_START);
if (ret < 0) {
ALOGE("fail to ioctl: REPEATER_IOCTL_START");
return ret;
}
ALOGI("repeater start success");
return ret;
}
int repeater_stop(void *handle)
{
int ret;
struct repeater_hal *hal;
if (!handle)
return -ENOENT;
hal = (struct repeater_hal *)handle;
ret = ioctl(hal->repeater_fd, REPEATER_IOCTL_STOP);
if (ret < 0) {
ALOGE("fail to ioctl: REPEATER_IOCTL_STOP");
return ret;
}
ALOGI("repeater stop success");
return ret;
}
int repeater_pause(void *handle)
{
int ret;
struct repeater_hal *hal;
if (!handle)
return -ENOENT;
hal = (struct repeater_hal *)handle;
ret = ioctl(hal->repeater_fd, REPEATER_IOCTL_PAUSE);
if (ret < 0) {
ALOGE("fail to ioctl: REPEATER_IOCTL_PAUSE");
return ret;
}
ALOGI("repeater pause success");
return ret;
}
int repeater_resume(void *handle)
{
int ret;
struct repeater_hal *hal;
if (!handle)
return -ENOENT;
hal = (struct repeater_hal *)handle;
ret = ioctl(hal->repeater_fd, REPEATER_IOCTL_RESUME);
if (ret < 0) {
ALOGE("fail to ioctl: REPEATER_IOCTL_RESUME");
return ret;
}
ALOGI("repeater resume success");
return ret;
}
int repeater_get_idle(void *handle, int *idle) {
int ret;
struct repeater_hal *hal;
if (!handle)
return -ENOENT;
hal = (struct repeater_hal *)handle;
ret = ioctl(hal->repeater_fd, REPEATER_IOCTL_GET_IDLE_INFO, idle);
ALOGV("ioctl(REPEATER_IOCTL_GET_IDLE_INFO) ret %d, idle %d", ret, *idle);
return ret;
}
int repeater_dump(void *handle, char *name)
{
int ret;
struct repeater_hal *hal;
int buf_idx = -1;
int width, height;
int size;
if (!handle)
return -ENOENT;
hal = (struct repeater_hal *)handle;
ret = ioctl(hal->repeater_fd, REPEATER_IOCTL_DUMP, &buf_idx);
ALOGI("repeater_dump() ioctl ret %d, buf_idx %d", ret, buf_idx);
if (ret == 0 && buf_idx >= 0) {
FILE *pFile = fopen(name, "wb");
width = hal->info.width;
height = hal->info.height;
size = NV12N_Y_SIZE(width, height) + NV12N_CBCR_SIZE(width, height);
ALOGI("repeater_dump() fopen(%s) pFile %p, hal->buf_addr[buf_idx] %p, size %d",
name, pFile, hal->buf_addr[buf_idx], size);
ALOGI("repeater_dump(), width %d, height %d, NV12N_Y_SIZE() %d, NV12N_CBCR_SIZE() %d",
width, height, NV12N_Y_SIZE(width, height), NV12N_CBCR_SIZE(width, height));
if (pFile) {
if (hal->buf_addr[buf_idx]) {
fwrite(hal->buf_addr[buf_idx], 0x1, width * height, pFile);
fwrite((char *)(hal->buf_addr[buf_idx]) + NV12N_Y_SIZE(width, height), 0x1, (width * height) / 2, pFile);
}
fclose(pFile);
}
}
return ret;
}