* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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.
*/
#include "display_layer.h"
#include <cerrno>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <securec.h>
#include "display_type.h"
#include "hdf_log.h"
#include "hdf_io_service_if.h"
#include "hdf_sbuf.h"
#include "osal_mem.h"
#define DEV_ID 0
#define LAYER_ID 0
#define FB_PATH "/dev/fb0"
#define DISP_WIDTH 800
#define DISP_HEIGHT 480
#define BITS_PER_PIXEL 32
#define BITS_TO_BYTE 8
#define DISP_SERVICE_NAME "hdf_disp"
#define DISP_CMD_GET_PANELINFO 1
#undef HDF_LOG_TAG
#define HDF_LOG_TAG display_layer_c
enum IntfSync {
OUTPUT_USER = 0,
OUTPUT_PAL,
OUTPUT_NTSC,
OUTPUT_1080P24,
OUTPUT_1080P25,
OUTPUT_1080P30,
OUTPUT_720P50,
OUTPUT_720P60,
OUTPUT_1080I50,
OUTPUT_1080I60,
OUTPUT_1080P50,
OUTPUT_1080P60,
OUTPUT_576P50,
OUTPUT_480P60,
OUTPUT_800X600_60,
OUTPUT_1024X768_60,
OUTPUT_1280X1024_60,
OUTPUT_1366X768_60,
OUTPUT_1440X900_60,
OUTPUT_1280X800_60,
OUTPUT_1600X1200_60,
OUTPUT_1680X1050_60,
OUTPUT_1920X1200_60,
OUTPUT_640X480_60,
OUTPUT_960H_PAL,
OUTPUT_960H_NTSC,
OUTPUT_1920X2160_30,
OUTPUT_2560X1440_30,
OUTPUT_2560X1440_60,
OUTPUT_2560X1600_60,
OUTPUT_3840X2160_24,
OUTPUT_3840X2160_25,
OUTPUT_3840X2160_30,
OUTPUT_3840X2160_50,
OUTPUT_3840X2160_60,
OUTPUT_4096X2160_24,
OUTPUT_4096X2160_25,
OUTPUT_4096X2160_30,
OUTPUT_4096X2160_50,
OUTPUT_4096X2160_60,
OUTPUT_320X240_60,
OUTPUT_320X240_50,
OUTPUT_240X320_50,
OUTPUT_240X320_60,
OUTPUT_800X600_50,
OUTPUT_720X1280_60,
OUTPUT_1080X1920_60,
OUTPUT_7680X4320_30,
};
struct DispInfo {
uint32_t width;
uint32_t hbp;
uint32_t hfp;
uint32_t hsw;
uint32_t height;
uint32_t vbp;
uint32_t vfp;
uint32_t vsw;
uint32_t frameRate;
uint32_t intfType;
enum IntfSync intfSync;
uint32_t minLevel;
uint32_t maxLevel;
uint32_t defLevel;
};
struct LayerPrivate {
int32_t fd;
uint32_t width;
uint32_t height;
int32_t pitch;
void *fbAddr;
uint32_t fbSize;
void *layerAddr;
PixelFormat pixFmt;
};
struct LayerManager {
pthread_mutex_t mutex;
pthread_mutexattr_t mutexattr;
int32_t count;
};
static struct LayerManager g_layerManager;
static void GetLayerMgr(void)
{
g_layerManager.count++;
}
static int32_t PutLayerMgr(void)
{
g_layerManager.count--;
return g_layerManager.count;
}
static void LockLayerMgr(void)
{
pthread_mutex_lock(&g_layerManager.mutex);
}
static void UnlockLayerMgr(void)
{
pthread_mutex_unlock(&g_layerManager.mutex);
}
static int32_t DispCmdSend(const uint32_t cmd, struct HdfSBuf *reqData, struct HdfSBuf *respData)
{
struct HdfIoService *dispService = NULL;
dispService = HdfIoServiceBind(DISP_SERVICE_NAME);
if ((dispService == NULL) || (dispService->dispatcher == NULL) || (dispService->dispatcher->Dispatch == NULL)) {
HDF_LOGE("%s:bad remote service found", __func__);
return DISPLAY_FAILURE;
}
int32_t ret = dispService->dispatcher->Dispatch(&dispService->object, cmd, reqData, respData);
if (ret != DISPLAY_SUCCESS) {
HDF_LOGE("%s: cmd=%u, ret=%d", __func__, cmd, ret);
HdfIoServiceRecycle(dispService);
return DISPLAY_FAILURE;
}
HdfIoServiceRecycle(dispService);
return DISPLAY_SUCCESS;
}
static int32_t GetInfo(uint32_t devId, struct DispInfo *info)
{
struct DispInfo *tmpInfo = NULL;
struct HdfSBuf *data = NULL;
struct HdfSBuf *reply = NULL;
if (info == NULL) {
HDF_LOGE("%s: invalid param", __func__);
return DISPLAY_FAILURE;
}
data = HdfSbufObtainDefaultSize();
if (data == NULL) {
HDF_LOGE("%s: obtain data sbuf fail", __func__);
return DISPLAY_FAILURE;
}
reply = HdfSbufObtainDefaultSize();
if (reply == NULL) {
HDF_LOGE("%s: obtain reply sbuf fail", __func__);
HdfSbufRecycle(data);
return DISPLAY_FAILURE;
}
if (!HdfSbufWriteUint32(data, devId)) {
HDF_LOGE("HdfSbufWriteUint32 failure");
goto ERR;
}
if (DispCmdSend(DISP_CMD_GET_PANELINFO, data, reply) != DISPLAY_SUCCESS) {
HDF_LOGE("cmd:DISP_CMD_GET_PANEL_INFO failure");
goto ERR;
}
uint32_t dataSize = 0;
if (!HdfSbufReadBuffer(reply, (const void **)(&tmpInfo), &dataSize) || dataSize != sizeof(struct DispInfo)) {
HDF_LOGE("HdfSbufReadBuffer failure");
goto ERR;
}
if (memcpy_s(info, sizeof(struct DispInfo), tmpInfo, dataSize) != EOK) {
HDF_LOGE("memcpy_s failure");
goto ERR;
}
HdfSbufRecycle(data);
HdfSbufRecycle(reply);
return DISPLAY_SUCCESS;
ERR:
HdfSbufRecycle(data);
HdfSbufRecycle(reply);
return DISPLAY_FAILURE;
}
static struct LayerPrivate *GetLayerInstance(void)
{
static int32_t count;
static struct DispInfo info;
static struct LayerPrivate layerPriv = {
.fd = -1,
.width = DISP_WIDTH,
.height = DISP_HEIGHT,
.pixFmt = PIXEL_FMT_RGBA_8888,
};
if (count == 0) {
count = 1;
if (GetInfo(DEV_ID, &info) == DISPLAY_SUCCESS) {
layerPriv.width = info.width;
layerPriv.height = info.height;
} else {
HDF_LOGI("%s: GetInfo failed, use default setting", __func__);
}
}
return &layerPriv;
}
static int32_t InitDisplay(uint32_t devId)
{
if (devId != DEV_ID) {
HDF_LOGE("%s: devId invalid", __func__);
return DISPLAY_FAILURE;
}
return DISPLAY_SUCCESS;
}
static int32_t DeinitDisplay(uint32_t devId)
{
if (devId != DEV_ID) {
HDF_LOGE("%s: devId invalid", __func__);
return DISPLAY_FAILURE;
}
return DISPLAY_SUCCESS;
}
static void SetBackground(void)
{
struct LayerPrivate *priv = GetLayerInstance();
uint32_t i;
uint32_t j;
uint32_t *framebuffer = (uint32_t *)priv->fbAddr;
for (j = 0; j < priv->height; j++) {
for (i = 0; i < priv->width; i++) {
framebuffer[i + j * priv->width] = 0xFF;
}
}
}
static int32_t CreateLayer(uint32_t devId, const LayerInfo *layerInfo, uint32_t *layerId)
{
if (layerInfo == NULL || layerId == NULL) {
HDF_LOGE("%s: pointer is null", __func__);
return DISPLAY_NULL_PTR;
}
if (devId != DEV_ID) {
HDF_LOGE("%s: devId invalid", __func__);
return DISPLAY_FAILURE;
}
LockLayerMgr();
struct LayerPrivate *priv = GetLayerInstance();
priv->fd = open(FB_PATH, O_RDWR, 0);
if (priv->fd < 0) {
HDF_LOGE("%s: open fb dev failed", __func__);
UnlockLayerMgr();
return DISPLAY_FD_ERR;
}
priv->pitch = layerInfo->width * BITS_PER_PIXEL / BITS_TO_BYTE;
priv->fbSize = ((priv->pitch * priv->height) + 0xfff) & (~0xfff);
priv->fbAddr = (void *)mmap(NULL, priv->fbSize, PROT_READ | PROT_WRITE, MAP_SHARED, priv->fd, 0);
if (priv->fbAddr == MAP_FAILED) {
HDF_LOGE("%s: mmap fb address failure, errno: %d", __func__, errno);
close(priv->fd);
priv->fd = -1;
priv->pitch = 0;
priv->fbSize = 0;
UnlockLayerMgr();
return DISPLAY_FAILURE;
}
SetBackground();
*layerId = LAYER_ID;
HDF_LOGI("%s: open layer success", __func__);
UnlockLayerMgr();
return DISPLAY_SUCCESS;
}
static int32_t CloseLayer(uint32_t devId, uint32_t layerId)
{
if (devId != DEV_ID) {
HDF_LOGE("%s: devId invalid", __func__);
return DISPLAY_FAILURE;
}
if (layerId != LAYER_ID) {
HDF_LOGE("%s: layerId invalid", __func__);
return DISPLAY_FAILURE;
}
LockLayerMgr();
struct LayerPrivate *priv = GetLayerInstance();
if (priv->fd >= 0) {
close(priv->fd);
}
if (priv->layerAddr != NULL) {
free(priv->layerAddr);
priv->layerAddr = NULL;
}
if (priv->fbAddr != NULL) {
munmap(priv->fbAddr, priv->fbSize);
}
priv->fd = -1;
UnlockLayerMgr();
return DISPLAY_SUCCESS;
}
static int32_t GetDisplayInfo(uint32_t devId, DisplayInfo *dispInfo)
{
if (dispInfo == NULL) {
HDF_LOGE("%s: dispInfo is null", __func__);
return DISPLAY_NULL_PTR;
}
if (devId != DEV_ID) {
HDF_LOGE("%s: devId invalid", __func__);
return DISPLAY_FAILURE;
}
LockLayerMgr();
struct LayerPrivate *priv = GetLayerInstance();
dispInfo->width = priv->width;
dispInfo->height = priv->height;
dispInfo->rotAngle = ROTATE_NONE;
HDF_LOGD("%s: width = %u, height = %u, rotAngle = %u", __func__, dispInfo->width,
dispInfo->height, dispInfo->rotAngle);
UnlockLayerMgr();
return DISPLAY_SUCCESS;
}
static int32_t Flush(uint32_t devId, uint32_t layerId, LayerBuffer *buffer)
{
int32_t ret;
if (devId != DEV_ID) {
HDF_LOGE("%s: devId invalid", __func__);
return DISPLAY_FAILURE;
}
if (layerId != LAYER_ID) {
HDF_LOGE("%s: layerId invalid", __func__);
return DISPLAY_FAILURE;
}
if (buffer == NULL) {
HDF_LOGE("%s: buffer is null", __func__);
return DISPLAY_FAILURE;
}
HDF_LOGD("%s: width = %d, height = %d, pixFormat = %d, pitch = %d", __func__, buffer->width,
buffer->height, buffer->pixFormat, buffer->pitch);
LockLayerMgr();
struct LayerPrivate *priv = GetLayerInstance();
ret = memcpy_s(priv->fbAddr, priv->fbSize, buffer->data.virAddr, priv->fbSize);
if (ret != EOK) {
HDF_LOGE("%s: memcpy_s fail, ret %d", __func__, ret);
UnlockLayerMgr();
return ret;
}
UnlockLayerMgr();
return DISPLAY_SUCCESS;
}
static int32_t GetLayerBuffer(uint32_t devId, uint32_t layerId, LayerBuffer *buffer)
{
if (buffer == NULL) {
HDF_LOGE("%s: buffer is null", __func__);
return DISPLAY_NULL_PTR;
}
if (devId != DEV_ID) {
HDF_LOGE("%s: devId invalid", __func__);
return DISPLAY_FAILURE;
}
if (layerId != LAYER_ID) {
HDF_LOGE("%s: layerId invalid", __func__);
return DISPLAY_FAILURE;
}
LockLayerMgr();
struct LayerPrivate *priv = GetLayerInstance();
if (priv->fd < 0) {
HDF_LOGE("%s: fd invalid", __func__);
UnlockLayerMgr();
return DISPLAY_FAILURE;
}
buffer->fenceId = 0;
buffer->width = priv->width;
buffer->height = priv->height;
buffer->pixFormat = priv->pixFmt;
buffer->pitch = priv->pitch;
buffer->data.virAddr = malloc(priv->fbSize);
if (buffer->data.virAddr == NULL) {
HDF_LOGE("%s: malloc failure", __func__);
UnlockLayerMgr();
return DISPLAY_FAILURE;
}
priv->layerAddr = buffer->data.virAddr;
(void)memset_s(buffer->data.virAddr, priv->fbSize, 0x00, priv->fbSize);
HDF_LOGD("%s: fenceId = %d, width = %d, height = %d, pixFormat = %d, pitch = %d", __func__, buffer->fenceId,
buffer->width, buffer->height, buffer->pixFormat, buffer->pitch);
UnlockLayerMgr();
return DISPLAY_SUCCESS;
}
int32_t LayerInitialize(LayerFuncs **funcs)
{
static LayerFuncs *lFuncs = NULL;
if (funcs == NULL) {
HDF_LOGE("%s: funcs is null", __func__);
return DISPLAY_NULL_PTR;
}
if (lFuncs == NULL) {
lFuncs = (LayerFuncs *)OsalMemCalloc(sizeof(LayerFuncs));
if (lFuncs == NULL) {
HDF_LOGE("%s: lFuncs is null", __func__);
return DISPLAY_NULL_PTR;
}
pthread_mutexattr_init(&g_layerManager.mutexattr);
pthread_mutexattr_setpshared(&g_layerManager.mutexattr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&g_layerManager.mutex, &g_layerManager.mutexattr);
lFuncs->InitDisplay = InitDisplay;
lFuncs->DeinitDisplay = DeinitDisplay;
lFuncs->GetDisplayInfo = GetDisplayInfo;
lFuncs->CreateLayer = CreateLayer;
lFuncs->CloseLayer = CloseLayer;
lFuncs->Flush = Flush;
lFuncs->GetLayerBuffer = GetLayerBuffer;
}
*funcs = lFuncs;
GetLayerMgr();
HDF_LOGI("%s: success", __func__);
return DISPLAY_SUCCESS;
}
int32_t LayerUninitialize(LayerFuncs *funcs)
{
if (funcs == NULL) {
HDF_LOGE("%s: funcs is null", __func__);
return DISPLAY_NULL_PTR;
}
if (PutLayerMgr() == 0) {
pthread_mutexattr_destroy(&g_layerManager.mutexattr);
pthread_mutex_destroy(&g_layerManager.mutex);
OsalMemFree(funcs);
}
HDF_LOGI("%s: layer uninitialize success", __func__);
return DISPLAY_SUCCESS;
}