/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * libuvc-camera (camera link and rkaiq) * * Copyright (C) 2022 Rockchip Electronics Co., Ltd. * * Author: Bin Yang * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 mSensorInfos; std::map 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, ¶ms)) { 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& 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; }