android13/external/uvc-gadget/libuvc-camera/uvc_camera.cpp

1291 lines
37 KiB
C++
Executable File

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* libuvc-camera (camera link and rkaiq)
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*
* Author: Bin Yang <yangbin@rock-chips.com>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <mediactl.h>
#include <mediactl/mediactl-priv.h>
#include <linux/v4l2-subdev.h>
#include <linux/videodev2.h>
#include <log/log.h>
#include <vector>
#include <map>
#include "rkisp_control_loop.h"
#include "rkisp_control_aiq.h"
#include "tinyxml2.h"
#include "uvc-camera.h"
#define CLEAR(x) memset(&(x), 0, sizeof(x))
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "UVC-RKCAM"
#define rkaiq_info(format, ...) ALOGI(format, ##__VA_ARGS__)
#define rkaiq_warn(format, ...) ALOGW(format, ##__VA_ARGS__)
#define rkaiq_err(format, ...) ALOGE(format, ##__VA_ARGS__)
/* Private v4l2 event */
#define CIFISP_V4L2_EVENT_STREAM_START \
(V4L2_EVENT_PRIVATE_START + 1)
#define CIFISP_V4L2_EVENT_STREAM_STOP \
(V4L2_EVENT_PRIVATE_START + 2)
#define FILE_PATH_LEN 64
#define CAMS_NUM_MAX 3
#define FLASH_NUM_MAX 3
#define MAX_MEDIA_DEV_NUM 2 * CAMS_NUM_MAX
enum media_type {
MEDIA_UNKNOWN = 0,
MEDIA_RKCIF,
MEDIA_RKISP
};
struct UVC_Cam_Info {
char dev_name[FILE_PATH_LEN];
char sensor_name[FILE_PATH_LEN];
char model_name[FILE_PATH_LEN];
char mipi_name[FILE_PATH_LEN];
char phy_name[FILE_PATH_LEN];
char isp_name[FILE_PATH_LEN];
struct v4l2_pix_format format;
};
/* The SensorDriverDescriptor instance that describes sensor device and
* connected sub-device informations.
* @sensor_entity_name,
* @sd_isp_path, the isp sub-device path, e.g. /dev/v4l-subdev0
* @vd_params_path, the params video device path
* @vd_stats_path, the stats video device path
* @cams, multipe cameras can attache to isp, but only one can be active
* @sd_sensor_path, the sensor sub-device path
* @sd_lens_path, the lens sub-device path that attached to sensor
* @sd_flash_path, the flash sub-device path that attached to sensor,
* can be two or more.
* @link_enabled, the link status of this sensor
*/
struct SensorDriverDescriptor {
/* sensor entity name format:
* m01_b_ov13850 1-0010, where 'm01' means
* module index number, 'b' means
* back or front, 'ov13850' is real
* sensor name, '1-0010' means the i2c bus
* and sensor i2c slave address
*/
int module_idx;
char sensor_entity_name[FILE_PATH_LEN];
char sd_sensor_path[FILE_PATH_LEN];
char sd_lens_path[FILE_PATH_LEN];
char sd_flash_path[FLASH_NUM_MAX][FILE_PATH_LEN];
bool link_enabled;
bool sensorLinkedToCIF;
char linkedModelName[32];
std::string mSensorName;
std::string mDeviceName;
std::string mParentMediaDev;
std::string mModuleRealSensorName; //parsed frome sensor entity name
std::string mModuleIndexStr; // parsed from sensor entity name
char mPhyModuleOrient; // parsed from sensor entity name
};
std::vector<struct SensorDriverDescriptor> mSensorInfos;
std::map<uint32_t, const char*> mHdrModeConfigs;
/* The media topology instance that describes video device and
* sub-device informations.
*
* @sd_isp_path, the isp sub-device path, e.g. /dev/v4l-subdev0
* @vd_params_path, the params video device path
* @vd_stats_path, the stats video device path
* @cams, multipe cameras can attache to isp, but only one can be active
* @sd_sensor_path, the sensor sub-device path
* @sd_lens_path, the lens sub-device path that attached to sensor
* @sd_flash_path, the flash sub-device path that attached to sensor,
* can be two or more.
* @link_enabled, the link status of this sensor
*/
struct rkisp_media_info {
char sd_isp_path[FILE_PATH_LEN];
char vd_params_path[FILE_PATH_LEN];
char vd_stats_path[FILE_PATH_LEN];
SensorDriverDescriptor sensorInfo;
const char *hdrmode;
char mdev_path[32];
int isp_fd;
int available;
void* aiq_ctx;
};
static struct rkisp_media_info media_infos[CAMS_NUM_MAX];
static struct UVC_Cam_Info uvc_cams[CAMS_NUM_MAX];
static void* rkisp_engine;
static const char *hdrmode = "NORMAL";
static int width = 2688;
static int height = 1520;
const char* kDefaultCfgPath = "/vendor/etc/multi_camera_config.xml";
static int xioctl(int fh, int request, void *arg)
{
int r;
do {
r = ioctl(fh, request, arg);
} while (-1 == r && EINTR == errno);
return r;
}
static int v4l2_subdev_open(struct media_entity *entity)
{
if (entity->fd != -1)
return 0;
entity->fd = open(entity->devname, O_RDWR);
if (entity->fd == -1) {
int ret = -errno;
rkaiq_err("%s: Failed to open subdev device node %s\n", __func__,
entity->devname);
return ret;
}
return 0;
}
static void v4l2_subdev_close(struct media_entity *entity)
{
close(entity->fd);
entity->fd = -1;
}
static int v4l2_subdev_get_format(struct media_entity *entity,
struct v4l2_mbus_framefmt *format)
{
struct v4l2_subdev_format fmt;
int ret = 0;
ret = v4l2_subdev_open(entity);
if (ret < 0)
return ret;
memset(&fmt, 0, sizeof(fmt));
fmt.pad = 0;
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
if (ret < 0) {
ret = -errno;
goto err;
}
*format = fmt.format;
err:
v4l2_subdev_close(entity);
return ret;
}
static int rkisp_get_devname(struct media_device *device, const char *name,
char *dev_name)
{
const char *devname;
media_entity *entity = NULL;
entity = media_get_entity_by_name(device, name, strlen(name));
if (!entity)
return -1;
devname = media_entity_get_devname(entity);
if (!devname) {
rkaiq_err("can't find %s device path!", name);
return -1;
}
strncpy(dev_name, devname, FILE_PATH_LEN);
rkaiq_info("get %s devname: %s\n", name, dev_name);
return 0;
}
static int parseModuleInfo(const std::string &entity_name,
SensorDriverDescriptor &drv_info)
{
int ret = 0;
/*
* sensor entity name format SHOULD be like this:
* m00_b_ov13850 1-0010
*/
if (entity_name.empty())
return -1;
int parse_index = 0;
if (entity_name.at(parse_index) != 'm') {
rkaiq_err("%d:parse sensor entity name %s error at %d, "
"please check sensor driver !\n",
__LINE__, entity_name.c_str(), parse_index);
return -1;
}
std::string index_str = entity_name.substr (parse_index, 3);
drv_info.mModuleIndexStr = index_str;
parse_index += 3;
if (entity_name.at(parse_index) != '_') {
rkaiq_err("%d:parse sensor entity name %s error at %d, "
"please check sensor driver !\n",
__LINE__, entity_name.c_str(), parse_index);
return -1;
}
parse_index++;
if (entity_name.at(parse_index) != 'b' &&
entity_name.at(parse_index) != 'f') {
rkaiq_err("%d:parse sensor entity name %s error at %d, "
"please check sensor driver !\n",
__LINE__, entity_name.c_str(), parse_index);
return -1;
}
drv_info.mPhyModuleOrient = entity_name.at(parse_index);
parse_index++;
if (entity_name.at(parse_index) != '_') {
rkaiq_err("%d:parse sensor entity name %s error at %d, "
"please check sensor driver !\n",
__LINE__, entity_name.c_str(), parse_index);
return -1;
}
parse_index++;
std::size_t real_name_end = std::string::npos;
if ((real_name_end = entity_name.find(' ')) == std::string::npos) {
rkaiq_err("%d:parse sensor entity name %s error at %d, "
"please check sensor driver !\n",
__LINE__, entity_name.c_str(), parse_index);
return -1;
}
std::string real_name_str = entity_name.substr(parse_index, real_name_end - parse_index);
drv_info.mModuleRealSensorName = real_name_str;
rkaiq_info("%s:%d, real sensor name %s, module ori %c, module id %s\n",
__FUNCTION__, __LINE__, drv_info.mModuleRealSensorName.c_str(),
drv_info.mPhyModuleOrient, drv_info.mModuleIndexStr.c_str());
return ret;
}
static int rkisp_enumrate_modules (struct media_device *device)
{
uint32_t nents, i;
const char* subdev_path = NULL;
int active_sensor = -1;
SensorDriverDescriptor drvInfo;
int ret;
const struct media_device_info *info = NULL;
CLEAR(drvInfo);
drvInfo.mSensorName = "none";
drvInfo.link_enabled = false;
nents = media_get_entities_count (device);
for (i = 0; i < nents; ++i) {
int module_idx = -1;
struct media_entity *e;
const struct media_entity_desc *ef;
const struct media_link *link;
e = media_get_entity(device, i);
ef = media_entity_get_info(e);
if (ef->type != MEDIA_ENT_T_V4L2_SUBDEV_SENSOR &&
ef->type != MEDIA_ENT_T_V4L2_SUBDEV_FLASH &&
ef->type != MEDIA_ENT_T_V4L2_SUBDEV_LENS)
continue;
if (ef->name[0] != 'm' && ef->name[3] != '_') {
rkaiq_err("sensor/lens/flash entity name format is incorrect,"
"pls check driver version !\n");
return -1;
}
/* Retrive the sensor index from sensor name,
* which is indicated by two characters after 'm',
* e.g. m00_b_ov13850 1-0010
* ^^, 00 is the module index
*/
module_idx = atoi(ef->name + 1);
if (module_idx >= CAMS_NUM_MAX) {
rkaiq_err("multiple sensors more than two not supported, %s\n", ef->name);
continue;
}
subdev_path = media_entity_get_devname (e);
switch (ef->type) {
case MEDIA_ENT_T_V4L2_SUBDEV_SENSOR:
drvInfo.module_idx = module_idx;
drvInfo.mSensorName = ef->name;
strncpy(drvInfo.sd_sensor_path,
subdev_path, FILE_PATH_LEN);
strcpy(drvInfo.sensor_entity_name, ef->name);
rkaiq_info("%s(%d) sensor_entity_name(%s)\n",
__FUNCTION__, __LINE__, drvInfo.sensor_entity_name);
ret = parseModuleInfo(drvInfo.mSensorName, drvInfo);
link = media_entity_get_link(e, 0);
if (link && (link->flags & MEDIA_LNK_FL_ENABLED)) {
drvInfo.link_enabled = true;
} else {
rkaiq_info("%s(%d) sensor(%s) not linked!\n",
__FUNCTION__, __LINE__, drvInfo.mSensorName.c_str());
}
break;
case MEDIA_ENT_T_V4L2_SUBDEV_FLASH:
// TODO, support multiple flashes attached to one module
strncpy(drvInfo.sd_flash_path[0],
subdev_path, FILE_PATH_LEN);
break;
case MEDIA_ENT_T_V4L2_SUBDEV_LENS:
strncpy(drvInfo.sd_lens_path,
subdev_path, FILE_PATH_LEN);
break;
default:
break;
}
}
if (drvInfo.mSensorName != "none" && drvInfo.link_enabled) {
info = media_get_info(device);
if (info && !strncmp(info->driver, "rkcif", strlen("rkcif"))) {
drvInfo.sensorLinkedToCIF = true;
} else {
drvInfo.sensorLinkedToCIF = false;
}
strncpy(drvInfo.linkedModelName, info->model, sizeof(info->model));
rkaiq_info("module_idx(%d) sensor_entity_name(%s), linkedModelName(%s).\n",
drvInfo.module_idx, drvInfo.sensor_entity_name, drvInfo.linkedModelName);
mSensorInfos.push_back(drvInfo);
//media_infos[drvInfo.module_idx].sensorInfo = drvInfo;
} else {
rkaiq_info("media path: %s, no camera sensor found!\n", device->devnode);
}
return 0;
}
static bool compareFuncForSensorInfo(struct SensorDriverDescriptor s1,
struct SensorDriverDescriptor s2) {
return (s1.mModuleIndexStr < s2.mModuleIndexStr);
}
/* get sensor media info */
static int rkisp_get_sensor_info() {
int ret = 0;
unsigned int i, index = 0;
char sys_path[64];
int find_sensor = 0;
int find_isp = 0;
int linked_sensor = -1;
struct media_device *device = NULL;
while (index < MAX_MEDIA_DEV_NUM) {
snprintf(sys_path, 64, "/dev/media%d", index++);
//rkaiq_info("media get sys_path: %s\n", sys_path);
if(access(sys_path,F_OK))
continue;
device = media_device_new(sys_path);
if (device == NULL) {
rkaiq_err("Failed to create media %s\n", sys_path);
continue;
}
ret = media_device_enumerate(device);
if (ret < 0) {
rkaiq_err("Failed to enumerate %s (%d)\n", sys_path, ret);
media_device_unref(device);
continue;
}
ret = rkisp_enumrate_modules(device);
if (ret < 0) {
rkaiq_err("Failed to enumerate modules%s (%d)\n", sys_path, ret);
media_device_unref(device);
continue;
}
media_device_unref(device);
}
std:sort(mSensorInfos.begin(), mSensorInfos.end(), compareFuncForSensorInfo);
if (mSensorInfos.size() == 0) {
// No registered drivers found
rkaiq_err("ERROR no sensor driver registered in medias!\n");
ret = -1;
}
rkaiq_info("%s:%d, find available camera num:%d!\n", __FUNCTION__,
__LINE__, (unsigned int)mSensorInfos.size());
for (size_t i = 0; i < mSensorInfos.size(); i++) {
media_infos[i].sensorInfo = mSensorInfos[i];
rkaiq_info("media_infos: module_idx(%d) sensor_entity_name(%s)\n",
media_infos[i].sensorInfo.module_idx,
media_infos[i].sensorInfo.sensor_entity_name);
}
return ret;
}
/* Get sensor binded isp subdevs */
static int rkisp_enumrate_ispdev_info (struct media_device *device)
{
uint32_t nents, i;
const char* subdev_path = NULL;
int active_sensor = -1;
SensorDriverDescriptor drvInfo;
int ret;
const struct media_device_info *info = NULL;
char Temp[FILE_PATH_LEN];
CLEAR(drvInfo);
drvInfo.mSensorName = "none";
for (size_t i = 0; i < mSensorInfos.size(); i++) {
drvInfo = media_infos[i].sensorInfo;
rkaiq_info("@%s, Target sensor name: %s, candidate media: %s.\n",
__FUNCTION__, drvInfo.mSensorName.c_str(), device->devnode);
if (drvInfo.sensorLinkedToCIF) {
ret = rkisp_get_devname(device, drvInfo.linkedModelName, Temp);
if (ret < 0) {
rkaiq_err("%s is direct linked to sensor, not linked to cif!\n", device->devnode);
continue;
}
ret = rkisp_get_devname(device, "rkisp-isp-subdev", media_infos[i].sd_isp_path);
ret |= rkisp_get_devname(device, "rkisp-input-params", media_infos[i].vd_params_path);
ret |= rkisp_get_devname(device, "rkisp-statistics", media_infos[i].vd_stats_path);
strncpy(media_infos[i].mdev_path, device->devnode, sizeof(media_infos[i].mdev_path));
} else {
ret = rkisp_get_devname(device, drvInfo.sensor_entity_name, Temp);
if (ret < 0) {
rkaiq_err("%s not direct linked to sensor!\n", device->devnode);
continue;
}
ret = rkisp_get_devname(device, "rkisp-isp-subdev", media_infos[i].sd_isp_path);
ret |= rkisp_get_devname(device, "rkisp-input-params", media_infos[i].vd_params_path);
ret |= rkisp_get_devname(device, "rkisp-statistics", media_infos[i].vd_stats_path);
strncpy(media_infos[i].mdev_path, device->devnode, sizeof(media_infos[i].mdev_path));
}
}
return 0;
}
/* get sensor binded isp info */
static int rkisp_get_cif_linked_info() {
int ret = 0;
unsigned int i, index = 0;
char sys_path[64];
int find_sensor = 0;
int find_isp = 0;
int linked_sensor = -1;
struct media_device *device = NULL;
const struct media_device_info *info = NULL;
char model[64] = "\0";
while (index < MAX_MEDIA_DEV_NUM) {
info = NULL;
snprintf(sys_path, 64, "/dev/media%d", index++);
//rkaiq_info("media get sys_path: %s\n", sys_path);
if(access(sys_path,F_OK))
continue;
device = media_device_new(sys_path);
if (device == NULL) {
rkaiq_info("Failed to create media %s\n", sys_path);
continue;
}
ret = media_device_enumerate(device);
if (ret < 0) {
rkaiq_info("Failed to enumerate %s (%d)\n", sys_path, ret);
media_device_unref(device);
continue;
}
info = media_get_info(device);
if (info && !strncmp(info->driver, "rkcif", strlen("rkcif"))) {
rkaiq_info("media: %s is cif node, skip!\n", sys_path);
media_device_unref(device);
continue;
}
ret = rkisp_enumrate_ispdev_info(device);
if (ret < 0) {
rkaiq_err("Failed to enumerate ispdev info:%s (%d)\n", sys_path, ret);
media_device_unref(device);
continue;
}
media_device_unref(device);
}
return ret;
}
static int init_engine(struct rkisp_media_info *media_info)
{
int ret = 0;
for (int i = 0; i < CAMS_NUM_MAX; i++) {
if (!media_info->sensorInfo.link_enabled) {
rkaiq_info("Link disabled, skipped\n");
continue;
}
ret = rkisp_cl_rkaiq_init(&(media_info->aiq_ctx), NULL, NULL,
media_info->sensorInfo.sensor_entity_name);
if (ret) {
rkaiq_err("rkisp engine init failed !\n");
return -1;
}
/* Workaround: ISP read-back isuess */
if (mSensorInfos.size() > 2)
setMulCamConc(media_info->aiq_ctx, true);
break;
}
return 0;
}
static int prepare_engine(struct rkisp_media_info *media_info)
{
struct rkisp_cl_prepare_params_s params;
int ret = 0;
CLEAR(params);
params.isp_sd_node_path = media_info->sd_isp_path;
params.isp_vd_params_path = media_info->vd_params_path;
params.isp_vd_stats_path = media_info->vd_stats_path;
params.staticMeta = NULL;
params.width = width;
params.height = height;
params.work_mode = media_info->hdrmode;
rkaiq_info("%s--set workingmode(%s)\n", __FUNCTION__, params.work_mode);
for (int i = 0; i < CAMS_NUM_MAX; i++) {
if (!media_info->sensorInfo.link_enabled) {
rkaiq_info("Link disabled, skipped\n");
continue;
}
rkaiq_info("%s - %s: link enabled : %d\n",
media_info->sensorInfo.sd_sensor_path,
media_info->sensorInfo.sensor_entity_name,
media_info->sensorInfo.link_enabled);
if (strlen(media_info->sensorInfo.sd_lens_path))
params.lens_sd_node_path = media_info->sensorInfo.sd_lens_path;
if (strlen(media_info->sensorInfo.sd_flash_path[0]))
params.flashlight_sd_node_path[0] = media_info->sensorInfo.sd_flash_path[0];
params.sensor_sd_node_path = media_info->sensorInfo.sd_sensor_path;
if (rkisp_cl_prepare(media_info->aiq_ctx, &params)) {
rkaiq_err("rkisp engine prepare failed !\n");
return -1;
}
break;
}
return 0;
}
static int start_engine(struct rkisp_media_info *media_info)
{
rkaiq_info("rkaiq start\n");
rkisp_cl_start(media_info->aiq_ctx);
if (media_info->aiq_ctx == NULL) {
rkaiq_err("rkaiq_start engine failed\n");
return -1;
} else {
rkaiq_info("rkaiq_start engine succeed\n");
}
return 0;
}
static void stop_engine(struct rkisp_media_info *media_info)
{
rkisp_cl_stop(media_info->aiq_ctx);
}
static void deinit_engine(struct rkisp_media_info *media_info)
{
rkisp_cl_deinit(media_info->aiq_ctx);
if (media_info->aiq_ctx)
media_info->aiq_ctx = NULL;
}
/* engine process */
static int engine_process(struct rkisp_media_info *media_info)
{
int ret = 0;
int isp_fd;
isp_fd = open(media_info->vd_params_path, O_RDWR);
if (isp_fd < 0) {
rkaiq_err("open %s failed %s\n", media_info->vd_params_path, strerror(errno));
return -1;
}
ret = init_engine(media_info);
if (ret)
goto err_exit;
rkaiq_info("%s: init engine success...\n", media_info->mdev_path);
ret = prepare_engine(media_info);
if (ret)
goto err_exit;
rkaiq_info("%s: wait stream start event success ...\n", media_info->mdev_path);
ret = start_engine(media_info);
if (ret)
goto err_exit;
media_info->isp_fd = isp_fd;
err_exit:
return ret;
}
static bool updateModeList(tinyxml2::XMLElement* modeList,
std::map<uint32_t, const char*>& modeConfigs) {
using namespace tinyxml2;
rkaiq_info("@%s enter!\n", __FUNCTION__);
XMLElement* row = modeList->FirstChildElement("CameraId");
while (row != nullptr) {
uint32_t moduleId;
const char * mode = nullptr;
moduleId = row->UnsignedAttribute("moduleId"),
mode = row->Attribute("hdrmode");
if (mode == nullptr) {
rkaiq_err("%s: mode Config list must config mode!", __FUNCTION__);
return false;
}
modeConfigs.insert(std::make_pair(moduleId, mode));
row = row->NextSiblingElement("CameraId");
}
return true;
}
static int loadFromCfg(const char* cfgPath) {
using namespace tinyxml2;
XMLDocument configXml;
int errorID;
errorID = configXml.LoadFile(cfgPath);
if (errorID != XML_SUCCESS) {
rkaiq_err("%s: Unable to load aiq camera config file: %s. ErrorID: %d\n",
__FUNCTION__, cfgPath, errorID);
return errorID;
} else {
rkaiq_err("%s: load aiq camera config succeed!\n", __FUNCTION__);
}
XMLElement *aiqCamConfig = configXml.FirstChildElement("AiqCameraConfig");
if (aiqCamConfig == nullptr) {
rkaiq_err("%s: no aiq camera config specified\n", __FUNCTION__);
return -1;
}
XMLElement *modelist = aiqCamConfig->FirstChildElement("modeConfigList");
if (modelist == nullptr) {
rkaiq_info("%s: no mode list specified\n", __FUNCTION__);
} else {
if (!updateModeList(modelist, mHdrModeConfigs)) {
return -1;
}
}
return 0;
}
static int uvc_rkaiq_setBrightness(unsigned short level)
{
for (int i = 0; i < mSensorInfos.size(); i++) {
if ((&media_infos[i])->aiq_ctx)
rkisp_cl_setBrightness((&media_infos[i])->aiq_ctx, level);
}
rkaiq_info("uvc_rkaiq_setBrightness: %d \n", level);
return 0;
}
static int uvc_rkaiq_getBrightness(unsigned short *level)
{
if ((&media_infos[0])->aiq_ctx)
rkisp_cl_getBrightness((&media_infos[0])->aiq_ctx, (unsigned int *)level);
return 0;
}
static int uvc_rkaiq_setContrast(unsigned short level)
{
for (int i = 0; i < mSensorInfos.size(); i++) {
if ((&media_infos[i])->aiq_ctx)
rkisp_cl_setContrast((&media_infos[i])->aiq_ctx, level);
}
rkaiq_info("uvc_rkaiq_setContrast: %d \n", level);
return 0;
}
static int uvc_rkaiq_getContrast(unsigned short *level)
{
if ((&media_infos[0])->aiq_ctx)
rkisp_cl_getContrast((&media_infos[0])->aiq_ctx, (unsigned int *)level);
return 0;
}
static int uvc_rkaiq_setSaturation(unsigned short level)
{
for (int i = 0; i < mSensorInfos.size(); i++) {
if ((&media_infos[i])->aiq_ctx)
rkisp_cl_setSaturation((&media_infos[i])->aiq_ctx, level);
}
rkaiq_info("uvc_rkaiq_setSaturation: %d \n", level);
return 0;
}
static int uvc_rkaiq_getSaturation(unsigned short *level)
{
if ((&media_infos[0])->aiq_ctx)
rkisp_cl_getSaturation((&media_infos[0])->aiq_ctx, (unsigned int *)level);
return 0;
}
int uvc_rkaiq_ct(struct uvc_request_param *param, struct uvc_request_ct *ct)
{
unsigned char scan_mode = 0x0;
switch (param->cs) {
case UVC_CT_CONTROL_UNDEFINED:
break;
case UVC_CT_SCANNING_MODE_CONTROL:
if (param->dir == USB_TRAN_IN) {
ct->scan_mode[U_CUR] = 0x0;
ct->scan_mode[U_MIN] = 0x0;
ct->scan_mode[U_MAX] = 0x0;
ct->scan_mode[U_DEF] = 0x0;
ct->scan_mode[U_RES] = 0x0;
} else {
scan_mode = ct->scan_mode[U_CUR];
}
break;
case UVC_CT_AE_MODE_CONTROL:
case UVC_CT_AE_PRIORITY_CONTROL:
case UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL:
case UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL:
case UVC_CT_FOCUS_ABSOLUTE_CONTROL:
case UVC_CT_FOCUS_RELATIVE_CONTROL:
case UVC_CT_FOCUS_AUTO_CONTROL:
case UVC_CT_IRIS_ABSOLUTE_CONTROL:
case UVC_CT_IRIS_RELATIVE_CONTROL:
case UVC_CT_ZOOM_ABSOLUTE_CONTROL:
case UVC_CT_ZOOM_RELATIVE_CONTROL:
case UVC_CT_PANTILT_ABSOLUTE_CONTROL:
case UVC_CT_PANTILT_RELATIVE_CONTROL:
case UVC_CT_ROLL_ABSOLUTE_CONTROL:
case UVC_CT_ROLL_RELATIVE_CONTROL:
case UVC_CT_PRIVACY_CONTROL:
break;
default:
break;
}
return 0;
}
int uvc_rkaiq_pu(struct uvc_request_param *param, struct uvc_request_pu *pu)
{
switch (param->cs) {
case UVC_PU_CONTROL_UNDEFINED:
break;
case UVC_PU_BACKLIGHT_COMPENSATION_CONTROL:
break;
case UVC_PU_BRIGHTNESS_CONTROL:
if (param->dir == USB_TRAN_IN) {
uvc_rkaiq_getBrightness(&pu->brightness[U_CUR]);
pu->brightness[U_MIN] = 0;
pu->brightness[U_MAX] = 255;
pu->brightness[U_DEF] = 128;
} else if (param->dir == USB_TRAN_OUT) {
uvc_rkaiq_setBrightness(pu->brightness[U_CUR]);
}
break;
case UVC_PU_CONTRAST_CONTROL:
if (param->dir == USB_TRAN_IN) {
uvc_rkaiq_getContrast(&pu->contrast[U_CUR]);
pu->contrast[U_MIN] = 0;
pu->contrast[U_MAX] = 255;
pu->contrast[U_DEF] = 128;
} else if (param->dir == USB_TRAN_OUT) {
uvc_rkaiq_setContrast(pu->contrast[U_CUR]);
}
break;
case UVC_PU_GAIN_CONTROL:
pu->gain[U_CUR] = 0x0;
break;
case UVC_PU_POWER_LINE_FREQUENCY_CONTROL:
pu->pl_freq[U_CUR] = 0x0;
break;
case UVC_PU_HUE_CONTROL:
pu->hue[U_CUR] = 0x0;
break;
case UVC_PU_SATURATION_CONTROL:
if (param->dir == USB_TRAN_IN) {
uvc_rkaiq_getSaturation(&pu->saturation[U_CUR]);
pu->saturation[U_MIN] = 0;
pu->saturation[U_MAX] = 255;
pu->saturation[U_DEF] = 128;
} else if (param->dir == USB_TRAN_OUT) {
uvc_rkaiq_setSaturation(pu->saturation[U_CUR]);
}
break;
case UVC_PU_SHARPNESS_CONTROL:
pu->sharpness[U_CUR] = 0x0;
break;
case UVC_PU_GAMMA_CONTROL:
pu->gamma[U_CUR] = 0x0;
break;
case UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL:
pu->wb_temp[U_CUR] = 0x0;
break;
case UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL:
pu->wb_temp_auto[U_CUR] = 0x0;
break;
case UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL:
pu->wb_component[U_CUR] = 0x0;
break;
case UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL:
pu->wb_component_auto[U_CUR] = 0x0;
break;
case UVC_PU_DIGITAL_MULTIPLIER_CONTROL:
pu->digital_mult[U_CUR] = 0x0;
break;
case UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL:
pu->digital_mult_limit[U_CUR] = 0x0;
break;
case UVC_PU_HUE_AUTO_CONTROL:
pu->hue_auto[U_CUR] = 0x0;
break;
case UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL:
pu->analog_video[U_CUR] = 0x0;
break;
case UVC_PU_ANALOG_LOCK_STATUS_CONTROL:
pu->analog_lock[U_CUR] = 0x0;
break;
default:
break;
}
return 0;
}
int uvc_rkaiq_start(void)
{
int i = 0, ret = 0;
for (i = 0; i < mSensorInfos.size(); i++) {
rkaiq_info("uvc rkaiq start.\n");
engine_process(&media_infos[i]);
rkaiq_info("uvc rkaiq start success.\n");
}
return 0;
}
int uvc_rkaiq_stop(void)
{
int i = 0;
for (i = 0; i < mSensorInfos.size(); i++) {
rkaiq_info("uvc rkaiq stop.\n");
if (media_infos[i].isp_fd) {
stop_engine(&media_infos[i]);
deinit_engine(&media_infos[i]);
close(media_infos[i].isp_fd);
}
rkaiq_info("uvc rkaiq stop success.\n");
}
return 0;
}
static int uvc_camera_media_clr_index(unsigned int index)
{
char *command = NULL;
asprintf(&command,"/vendor/bin/media-ctl -d /dev/media%u -r", index);
system(command);
free(command);
rkaiq_info("clear rk camera media%u config.", index);
return 0;
}
static int uvc_camera_media_clr(void)
{
unsigned int index = 0;
char sys_path[64] = {0};
while (index < MAX_MEDIA_DEV_NUM) {
snprintf(sys_path, 64, "/dev/media%d", index);
if(!access(sys_path, F_OK))
uvc_camera_media_clr_index(index);
index++;
}
return 0;
}
static void camera_media_link(char media, const char *in_name, char in_num,
const char *out_name, char out_num, bool enable)
{
char *command = NULL;
asprintf(&command, "/vendor/bin/media-ctl -d /dev/media%u "
"-l '\"%s\":%u->\"%s\":%u[%d]'",
media, in_name, in_num, out_name, out_num, enable);
system(command);
free(command);
}
static int uvc_camera_media_cfg_index(enum media_type type,
unsigned int index, unsigned int cam_index)
{
const char *sensor_name = uvc_cams[cam_index].sensor_name;
const char *model_name = uvc_cams[cam_index].model_name;
const char *phy_name = uvc_cams[cam_index].phy_name;
const char *mipi_name = uvc_cams[cam_index].mipi_name;
const char *isp_name = uvc_cams[cam_index].isp_name;
const char *input_name = "rkisp-input-params";
#if defined(ISP_HW_V30)
if (type == MEDIA_RKCIF) {
camera_media_link(index, sensor_name, 0, phy_name, 0, 1);
camera_media_link(index, phy_name, 1, mipi_name, 0, 1);
camera_media_link(index, mipi_name, 1, "stream_cif_mipi_id0", 0, 1);
camera_media_link(index, mipi_name, 2, "stream_cif_mipi_id1", 0, 1);
camera_media_link(index, mipi_name, 3, "stream_cif_mipi_id2", 0, 1);
camera_media_link(index, mipi_name, 4, "stream_cif_mipi_id3", 0, 1);
camera_media_link(index, mipi_name, 5, "rkcif_scale_ch0", 0, 1);
camera_media_link(index, mipi_name, 6, "rkcif_scale_ch1", 0, 1);
camera_media_link(index, mipi_name, 7, "rkcif_scale_ch2", 0, 1);
camera_media_link(index, mipi_name, 8, "rkcif_scale_ch3", 0, 1);
} else if (type == MEDIA_RKISP) {
camera_media_link(index, model_name, 0, isp_name, 0, 1);
camera_media_link(index, input_name, 0, isp_name, 1, 1);
camera_media_link(index, isp_name, 3, "rkisp-statistics", 0, 1);
camera_media_link(index, isp_name, 2, "rkisp_mainpath", 0, 1);
camera_media_link(index, isp_name, 2, "rkisp_selfpath", 0, 1);
}
rkaiq_info("start rk3588 camera media%u config.", index);
#elif defined(ISP_HW_V21)
if (type == MEDIA_RKCIF) {
/* TODO */
} else if (type == MEDIA_RKISP) {
/* TODO */
}
rkaiq_info("start rk356x camera media%u config.", index);
#endif
return 0;
}
static int uvc_camera_media_cfg(unsigned int cam_num)
{
unsigned int index = 0;
unsigned int cam_index = 0;
char sys_path[64];
enum media_type type = MEDIA_UNKNOWN;
uvc_camera_media_clr();
while (index < MAX_MEDIA_DEV_NUM) {
snprintf(sys_path, 64, "/dev/media%d", index);
if(!access(sys_path, F_OK)) {
if (index < cam_num) {
type = MEDIA_RKCIF;
cam_index = index;
uvc_camera_media_cfg_index(type, index, cam_index);
} else if (index < 2*cam_num) {
type = MEDIA_RKISP;
cam_index = index - cam_num;
uvc_camera_media_cfg_index(type, index, cam_index);
}
}
index++;
}
return 0;
}
static enum media_type rkisp_get_device_info(struct media_device *device,
struct UVC_Cam_Info *uvc_cam)
{
uint32_t nents, i;
enum media_type type = MEDIA_UNKNOWN;
nents = media_get_entities_count (device);
for (i = 0; i < nents; ++i) {
const char* subdev_path = NULL;
struct media_entity *e;
const struct media_entity_desc *ef;
e = media_get_entity(device, i);
ef = media_entity_get_info(e);
subdev_path = media_entity_get_devname (e);
switch (ef->type) {
case MEDIA_ENT_T_V4L2_SUBDEV_SENSOR:
strcpy(uvc_cam->sensor_name, ef->name);
break;
case MEDIA_ENT_T_V4L2_SUBDEV:
if (strstr(ef->name, "dphy")) {
strcpy(uvc_cam->phy_name, ef->name);
} else if (strstr(ef->name, "mipi-csi")) {
strcpy(uvc_cam->mipi_name, ef->name);
type = MEDIA_RKCIF;
} else if (strstr(ef->name, "isp-subdev")) {
struct v4l2_mbus_framefmt format;
if (!v4l2_subdev_get_format(e, &format)) {
uvc_cam->format.width = format.width;
uvc_cam->format.height = format.height;
uvc_cam->format.pixelformat = format.code;
}
strcpy(uvc_cam->isp_name, ef->name);
type = MEDIA_RKISP;
} else if (strstr(ef->name, "lvds")) {
strcpy(uvc_cam->model_name, ef->name);
}
break;
case MEDIA_ENT_T_V4L2_VIDEO:
if (!strcmp(ef->name, "rkisp_mainpath"))
strcpy(uvc_cam->dev_name, subdev_path);
break;
default:
break;
}
}
return type;
}
static int rkisp_get_uvc_camera_info(unsigned int *cam_num)
{
int ret = 0;
unsigned int i, index = 0;
unsigned int cam_index = 0;
char sys_path[64];
struct media_device *device = NULL;
enum media_type type = MEDIA_UNKNOWN;
struct UVC_Cam_Info uvc_cam;
char devname[FILE_PATH_LEN];
CLEAR(uvc_cams);
while (index < MAX_MEDIA_DEV_NUM) {
snprintf(sys_path, 64, "/dev/media%d", index++);
if(access(sys_path,F_OK))
continue;
device = media_device_new(sys_path);
if (device == NULL) {
rkaiq_err("Failed to create media %s\n", sys_path);
continue;
}
ret = media_device_enumerate(device);
if (ret < 0) {
rkaiq_err("Failed to enumerate %s (%d)\n", sys_path, ret);
media_device_unref(device);
continue;
}
CLEAR(uvc_cam);
type = rkisp_get_device_info(device, &uvc_cam);
if (type == MEDIA_RKCIF) {
if ((cam_index >= CAMS_NUM_MAX) || ((index - 1) != cam_index)) {
rkaiq_err("get media cif info fail, index:%d, cam_index:%d, "
"CAMS_NUM_MAX:%d \n",
(index-1), cam_index, CAMS_NUM_MAX);
goto err;
}
memcpy(&uvc_cams[cam_index], &uvc_cam, sizeof(uvc_cam));
cam_index++;
} else if (type == MEDIA_RKISP) {
if (index - 1 < cam_index) {
rkaiq_err("get media isp info fail, index:%d, cam_index:%d\n",
(index-1), cam_index);
goto err;
}
memcpy(uvc_cams[index-cam_index-1].model_name, uvc_cam.model_name,
sizeof(uvc_cam.model_name));
memcpy(uvc_cams[index-cam_index-1].isp_name, uvc_cam.isp_name,
sizeof(uvc_cam.isp_name));
memcpy(uvc_cams[index-cam_index-1].dev_name, uvc_cam.dev_name,
sizeof(uvc_cam.dev_name));
memcpy(&uvc_cams[index-cam_index-1].format, &uvc_cam.format,
sizeof(uvc_cam.format));
}
err:
media_device_unref(device);
}
*cam_num = cam_index;
return ret;
}
int uvc_rkaiq_get_video(char ** cap_device, unsigned int index)
{
if (index >= CAMS_NUM_MAX) {
rkaiq_err("uvc get input device failed,"
"index:%d exceed %d\n", index, CAMS_NUM_MAX);
return -1;
}
*cap_device = uvc_cams[index].dev_name;
return 0;
}
int uvc_rkaiq_get_format(struct v4l2_pix_format *format, unsigned int index)
{
int ret = 0;
if (index >= CAMS_NUM_MAX) {
rkaiq_err("uvc get input format failed,"
"index:%d exceed %d\n", index, CAMS_NUM_MAX);
return -1;
}
*format = uvc_cams[index].format;
if (!format->width || !format->height) {
rkaiq_err("uvc get input size failed!\n");
ret = -1;
} else {
rkaiq_info("uvc get input size:%ux%u \n",
format->width, format->height);
}
return ret;
}
int uvc_rkaiq_init(bool link_en)
{
int i = 0;
unsigned int cam_num = 0;
CLEAR(media_infos);
mSensorInfos.clear();
mHdrModeConfigs.clear();
rkisp_get_uvc_camera_info(&cam_num);
if (link_en)
uvc_camera_media_cfg(cam_num);
/* get physical sensor infos */
if (rkisp_get_sensor_info()) {
rkaiq_err("Bad media topology error %d, %s\n", errno, strerror(errno));
return -errno;
}
/* get sensor binded isp infos */
if (rkisp_get_cif_linked_info()) {
rkaiq_err("Bad media info error %d, %s\n", errno, strerror(errno));
return -errno;
}
/* sensor mode config & mutex init */
loadFromCfg(kDefaultCfgPath);
if (mHdrModeConfigs.empty()) {
rkaiq_err("Using default hdr configs! (%s)\n", media_infos[i].mdev_path);
for (i = 0; i < mSensorInfos.size(); i++) {
media_infos[i].hdrmode = hdrmode;
}
} else {
for (i = 0; i < mSensorInfos.size(); i++) {
media_infos[i].hdrmode = mHdrModeConfigs[i];
rkaiq_info("camera:%d, hdrmode: %s.\n", i, media_infos[i].hdrmode);
}
}
return 0;
}
int uvc_rkaiq_deinit(bool link_en)
{
if (link_en)
uvc_camera_media_clr();
return 0;
}