Esempio n. 1
0
/**
 * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline
 * @pipe: The pipeline
 * @start: Start (when true) or stop (when false) the pipeline
 *
 * Walk the entities chain starting at the pipeline output video node and start
 * or stop all of them.
 *
 * Return: 0 if successful, or the return value of the failed video::s_stream
 * operation otherwise.
 */
static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
{
	struct xvip_dma *dma = pipe->output;
	struct media_entity *entity;
	struct media_pad *pad;
	struct v4l2_subdev *subdev;
	int ret;

	entity = &dma->video.entity;
	pad = NULL;

	while (1) {
		pad = xvip_get_entity_sink(entity, pad);
		if (pad == NULL)
			break;

		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;

		pad = media_entity_remote_pad(pad);
		if (pad == NULL ||
		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;

		entity = pad->entity;
		subdev = media_entity_to_v4l2_subdev(entity);

		ret = v4l2_subdev_call(subdev, video, s_stream, start);
		if (start && ret < 0 && ret != -ENOIOCTLCMD)
			return ret;
	}

	return 0;
}
Esempio n. 2
0
/**
 * media_entity_ops
 */
static int nxp_resc_link_setup(struct media_entity *entity,
        const struct media_pad *local,
        const struct media_pad *remote, u32 flags)
{
    switch (local->index | media_entity_type(remote->entity)) {
        case NXP_RESC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
            if (flags & MEDIA_LNK_FL_ENABLED)
                printk("%s: mlc connect to me\n", __func__);
            else
                printk("%s: mlc disconnect to me\n", __func__);
            break;

        case NXP_RESC_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
            if (flags & MEDIA_LNK_FL_ENABLED)
                printk("%s: I connect to HDMI\n", __func__);
            else
                printk("%s: I disconnect to HDMI\n", __func__);
            break;

        default:
            pr_err("%s: invalid link\n", __func__);
            return -EINVAL;
    }

    return 0;
}
Esempio n. 3
0
/*
 * vpfe_pipeline_disable() - Disable streaming on a pipeline
 * @vpfe_dev: vpfe device
 * @pipe: VPFE pipeline
 *
 * Walk the entities chain starting at the pipeline output video node and stop
 * all modules in the chain.
 *
 * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
 * can't be stopped.
 */
static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
{
	struct media_entity_graph graph;
	struct media_entity *entity;
	struct v4l2_subdev *subdev;
	struct media_device *mdev;
	int ret = 0;

	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
		entity = vpfe_get_input_entity(pipe->outputs[0]);
	else
		entity = &pipe->inputs[0]->video_dev.entity;

	mdev = entity->parent;
	mutex_lock(&mdev->graph_mutex);
	media_entity_graph_walk_start(&graph, entity);

	while ((entity = media_entity_graph_walk_next(&graph))) {

		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
			continue;
		subdev = media_entity_to_v4l2_subdev(entity);
		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			break;
	}
	mutex_unlock(&mdev->graph_mutex);

	return ret ? -ETIMEDOUT : 0;
}
Esempio n. 4
0
/*
 * unicam_pipeline_enable - enable streaming on a pipeline
 * @pipe: unicam pipeline
 * @mode: stream mode (single shot or continuous)
 *
 * Walk the entities chain starting at the pipeline output video node and start
 * all module in the chain in the given node.
 *
 * Return 0 if successful, or the return value of the failed video::s_stream
 * operation otherwise.
 */
static int unicam_pipeline_enable(struct unicam_pipeline *pipe,
		enum unicam_pipeline_stream_state mode)
{
	struct media_entity *entity;
	struct media_pad *pad;
	struct v4l2_subdev *subdev;
	int ret;

	entity = &pipe->output->video.entity;
	while (1) {
		pad = &entity->pads[0];
		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;

		pad = media_entity_remote_source(pad);
		if (pad == NULL ||
		media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;

		entity = pad->entity;
		subdev = media_entity_to_v4l2_subdev(entity);

		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return ret;

	}
	return 0;
}
static int tv_graph_pipeline_stream(struct mxr_pipeline *pipe, int on)
{
	struct mxr_device *mdev = pipe->layer->mdev;
	struct media_entity *me = &pipe->layer->vfd.entity;
	/* source pad of graphic layer entity */
	struct media_pad *pad = &me->pads[0];
	struct v4l2_subdev *sd;
	struct exynos_entity_data md_data;

	mxr_dbg(mdev, "%s TV graphic layer pipeline\n", on ? "start" : "stop");

	/* find remote pad through enabled link */
	pad = media_entity_remote_source(pad);
	if (pad == NULL)
		return -EPIPE;
	if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
		mxr_warn(mdev, "cannot find remote pad\n");

	sd = media_entity_to_v4l2_subdev(pad->entity);
	mxr_dbg(mdev, "s_stream of %s sub-device is called\n", sd->name);

	md_data.mxr_data_from = FROM_MXR_VD;
	v4l2_set_subdevdata(sd, &md_data);
	v4l2_subdev_call(sd, video, s_stream, on);

	return 0;
}
Esempio n. 6
0
/* Capture subdev media entity operations */
static int fimc_link_setup(struct media_entity *entity,
			   const struct media_pad *local,
			   const struct media_pad *remote, u32 flags)
{
	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);

	if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
		return -EINVAL;

	if (WARN_ON(fimc == NULL))
		return 0;

	dbg("%s --> %s, flags: 0x%x. input: 0x%x",
	    local->entity->name, remote->entity->name, flags,
	    fimc->vid_cap.input);

	if (flags & MEDIA_LNK_FL_ENABLED) {
		if (fimc->vid_cap.input != 0)
			return -EBUSY;
		fimc->vid_cap.input = sd->grp_id;
		return 0;
	}

	fimc->vid_cap.input = 0;
	return 0;
}
Esempio n. 7
0
static int fimc_md_link_notify(struct media_pad *source,
			       struct media_pad *sink, u32 flags)
{
	struct fimc_lite *fimc_lite = NULL;
	struct fimc_dev *fimc = NULL;
	struct fimc_pipeline *pipeline;
	struct v4l2_subdev *sd;
	int ret = 0;

	if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
		return 0;

	sd = media_entity_to_v4l2_subdev(sink->entity);

	switch (sd->grp_id) {
	case FLITE_GROUP_ID:
		fimc_lite = v4l2_get_subdevdata(sd);
		pipeline = &fimc_lite->pipeline;
		break;
	case FIMC_GROUP_ID:
		fimc = v4l2_get_subdevdata(sd);
		pipeline = &fimc->pipeline;
		break;
	default:
		return 0;
	}

	if (!(flags & MEDIA_LNK_FL_ENABLED)) {
		ret = __fimc_pipeline_close(pipeline);
		pipeline->subdevs[IDX_SENSOR] = NULL;
		pipeline->subdevs[IDX_CSIS] = NULL;

		if (fimc) {
			mutex_lock(&fimc->lock);
			fimc_ctrls_delete(fimc->vid_cap.ctx);
			mutex_unlock(&fimc->lock);
		}
		return ret;
	}
	/*
	 * Link activation. Enable power of pipeline elements only if the
	 * pipeline is already in use, i.e. its video node is opened.
	 * Recreate the controls destroyed during the link deactivation.
	 */
	if (fimc) {
		mutex_lock(&fimc->lock);
		if (fimc->vid_cap.refcnt > 0) {
			ret = __fimc_pipeline_open(pipeline,
						   source->entity, true);
		if (!ret)
			ret = fimc_capture_ctrls_create(fimc);
		}
		mutex_unlock(&fimc->lock);
	} else {
		mutex_lock(&fimc_lite->lock);
		ret = __fimc_pipeline_open(pipeline, source->entity, true);
		mutex_unlock(&fimc_lite->lock);
	}
	return ret ? -EPIPE : ret;
}
Esempio n. 8
0
/* Return a pointer to the ISP video instance at the far end of the pipeline. */
static struct isp_video *
isp_video_far_end(struct isp_video *video)
{
	struct media_entity_graph graph;
	struct media_entity *entity = &video->video.entity;
	struct media_device *mdev = entity->parent;
	struct isp_video *far_end = NULL;

	mutex_lock(&mdev->graph_mutex);
	media_entity_graph_walk_start(&graph, entity);

	while ((entity = media_entity_graph_walk_next(&graph))) {
		if (entity == &video->video.entity)
			continue;

		if (media_entity_type(entity) != MEDIA_ENTITY_TYPE_DEVNODE)
			continue;

		far_end = to_isp_video(media_entity_to_video_device(entity));
		if (far_end->type != video->type)
			break;

		far_end = NULL;
	}

	mutex_unlock(&mdev->graph_mutex);
	return far_end;
}
static int fimc_md_link_notify(struct media_pad *source,
			       struct media_pad *sink, u32 flags)
{
	struct v4l2_subdev *sd;
	struct fimc_dev *fimc;
	int ret = 0;

	if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
		return 0;

	sd = media_entity_to_v4l2_subdev(sink->entity);
	fimc = v4l2_get_subdevdata(sd);

	if (!(flags & MEDIA_LNK_FL_ENABLED)) {
		ret = __fimc_pipeline_shutdown(fimc);
		fimc->pipeline.sensor = NULL;
		fimc->pipeline.csis = NULL;

		mutex_lock(&fimc->lock);
		fimc_ctrls_delete(fimc->vid_cap.ctx);
		mutex_unlock(&fimc->lock);
		return ret;
	}
	mutex_lock(&fimc->lock);
	if (fimc->vid_cap.refcnt > 0) {
		ret = __fimc_pipeline_initialize(fimc, source->entity, true);
		if (!ret)
			ret = fimc_capture_ctrls_create(fimc);
	}
	mutex_unlock(&fimc->lock);

	return ret ? -EPIPE : ret;
}
Esempio n. 10
0
static int unicam_pipeline_disable(struct unicam_pipeline *pipe)
{
	struct media_entity *entity;
	struct media_pad *pad;
	struct v4l2_subdev *subdev;
	int failure = 0;

	entity = &pipe->output->video.entity;
	while (1) {
		pad = &entity->pads[0];
		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;

		pad = media_entity_remote_source(pad);
		if ((pad == NULL) ||
		media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;

		entity = pad->entity;
		subdev = media_entity_to_v4l2_subdev(entity);

		failure = v4l2_subdev_call(subdev, video, s_stream, 0);
	}

	return 0;
}
Esempio n. 11
0
/* make a note of pipeline details */
static void vpfe_prepare_pipeline(struct vpfe_video_device *video)
{
	struct media_entity *entity = &video->video_dev.entity;
	struct media_device *mdev = entity->parent;
	struct vpfe_pipeline *pipe = &video->pipe;
	struct vpfe_video_device *far_end = NULL;
	struct media_entity_graph graph;

	pipe->input_num = 0;
	pipe->output_num = 0;

	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
		pipe->inputs[pipe->input_num++] = video;
	else
		pipe->outputs[pipe->output_num++] = video;

	mutex_lock(&mdev->graph_mutex);
	media_entity_graph_walk_start(&graph, entity);
	while ((entity = media_entity_graph_walk_next(&graph))) {
		if (entity == &video->video_dev.entity)
			continue;
		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
			continue;
		far_end = to_vpfe_video(media_entity_to_video_device(entity));
		if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
			pipe->inputs[pipe->input_num++] = far_end;
		else
			pipe->outputs[pipe->output_num++] = far_end;
	}
	mutex_unlock(&mdev->graph_mutex);
}
Esempio n. 12
0
/* Capture subdev media entity operations */
static int fimc_lite_link_setup(struct media_entity *entity,
				const struct media_pad *local,
				const struct media_pad *remote, u32 flags)
{
	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
	unsigned int remote_ent_type = media_entity_type(remote->entity);
	int ret = 0;

	if (WARN_ON(fimc == NULL))
		return 0;

	v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x\n",
		 __func__, remote->entity->name, local->entity->name,
		 flags, fimc->source_subdev_grp_id);

	switch (local->index) {
	case FLITE_SD_PAD_SINK:
		if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) {
			ret = -EINVAL;
			break;
		}
		if (flags & MEDIA_LNK_FL_ENABLED) {
			if (fimc->source_subdev_grp_id == 0)
				fimc->source_subdev_grp_id = sd->grp_id;
			else
				ret = -EBUSY;
		} else {
			fimc->source_subdev_grp_id = 0;
			fimc->sensor = NULL;
		}
		break;

	case FLITE_SD_PAD_SOURCE_DMA:
		if (!(flags & MEDIA_LNK_FL_ENABLED))
			atomic_set(&fimc->out_path, FIMC_IO_NONE);
		else if (remote_ent_type == MEDIA_ENT_T_DEVNODE)
			atomic_set(&fimc->out_path, FIMC_IO_DMA);
		else
			ret = -EINVAL;
		break;

	case FLITE_SD_PAD_SOURCE_ISP:
		if (!(flags & MEDIA_LNK_FL_ENABLED))
			atomic_set(&fimc->out_path, FIMC_IO_NONE);
		else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
			atomic_set(&fimc->out_path, FIMC_IO_ISP);
		else
			ret = -EINVAL;
		break;

	default:
		v4l2_err(sd, "Invalid pad index\n");
		ret = -EINVAL;
	}
	mb();

	return ret;
}
Esempio n. 13
0
/**
 * fimc_pipeline_prepare - update pipeline information with subdevice pointers
 * @me: media entity terminating the pipeline
 *
 * Caller holds the graph mutex.
 */
static void fimc_pipeline_prepare(struct fimc_pipeline *p,
					struct media_entity *me)
{
	struct fimc_md *fmd = entity_to_fimc_mdev(me);
	struct v4l2_subdev *sd;
	struct v4l2_subdev *sensor = NULL;
	int i;

	for (i = 0; i < IDX_MAX; i++)
		p->subdevs[i] = NULL;

	while (1) {
		struct media_pad *pad = NULL;

		/* Find remote source pad */
		for (i = 0; i < me->num_pads; i++) {
			struct media_pad *spad = &me->pads[i];
			if (!(spad->flags & MEDIA_PAD_FL_SINK))
				continue;
			pad = media_entity_remote_source(spad);
			if (pad)
				break;
		}

		if (pad == NULL ||
		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;
		sd = media_entity_to_v4l2_subdev(pad->entity);

		switch (sd->grp_id) {
		case GRP_ID_SENSOR:
			sensor = sd;
			/* fall through */
		case GRP_ID_FIMC_IS_SENSOR:
			p->subdevs[IDX_SENSOR] = sd;
			break;
		case GRP_ID_CSIS:
			p->subdevs[IDX_CSIS] = sd;
			break;
		case GRP_ID_FLITE:
			p->subdevs[IDX_FLITE] = sd;
			break;
		case GRP_ID_FIMC:
			p->subdevs[IDX_FIMC] = sd;
			break;
		case GRP_ID_FIMC_IS:
			p->subdevs[IDX_IS_ISP] = sd;
			break;
		default:
			break;
		}
		me = &sd->entity;
		if (me->num_pads == 1)
			break;
	}

	if (sensor && p->subdevs[IDX_FIMC])
		__setup_sensor_notification(fmd, sensor, p->subdevs[IDX_FIMC]);
}
Esempio n. 14
0
int gsc_out_link_validate(const struct media_pad *source,
			  const struct media_pad *sink)
{
	struct v4l2_subdev_format src_fmt;
	struct v4l2_subdev_crop dst_crop;
	struct v4l2_subdev *sd;
	struct gsc_dev *gsc;
	struct gsc_frame *f;
	int ret;

	if (media_entity_type(source->entity) != MEDIA_ENT_T_V4L2_SUBDEV ||
	    media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) {
		gsc_err("media entity type isn't subdev\n");
		return 0;
	}

	sd = media_entity_to_v4l2_subdev(source->entity);
	gsc = entity_data_to_gsc(v4l2_get_subdevdata(sd));
	f = &gsc->out.ctx->d_frame;

	src_fmt.format.width = f->crop.width;
	src_fmt.format.height = f->crop.height;
	src_fmt.format.code = f->fmt->mbus_code;

	sd = media_entity_to_v4l2_subdev(sink->entity);
	/* To check if G-Scaler destination size and Mixer destinatin size
	   are the same */
	dst_crop.pad = sink->index;
	dst_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
	ret = v4l2_subdev_call(sd, pad, get_crop, NULL, &dst_crop);
	if (ret < 0 && ret != -ENOIOCTLCMD) {
		gsc_err("subdev get_fmt is failed\n");
		return -EPIPE;
	}

	if (src_fmt.format.width != dst_crop.rect.width ||
	    src_fmt.format.height != dst_crop.rect.height) {
		gsc_err("sink and source format is different\
			src_fmt.w = %d, src_fmt.h = %d,\
			dst_crop.w = %d, dst_crop.h = %d, rotation = %d",
			src_fmt.format.width, src_fmt.format.height,
			dst_crop.rect.width, dst_crop.rect.height,
			gsc->out.ctx->gsc_ctrls.rotate->val);
		return -EINVAL;
	}
Esempio n. 15
0
static int
v4l2_subdev_link_validate_get_format(struct media_pad *pad,
				     struct v4l2_subdev_format *fmt)
{
	switch (media_entity_type(pad->entity)) {
	case MEDIA_ENT_T_V4L2_SUBDEV:
		fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
		fmt->pad = pad->index;
		return v4l2_subdev_call(media_entity_to_v4l2_subdev(
						pad->entity),
					pad, get_fmt, NULL, fmt);
	default:
		WARN(1, "Driver bug! Wrong media entity type %d, entity %s\n",
		     media_entity_type(pad->entity), pad->entity->name);
		/* Fall through */
	case MEDIA_ENT_T_DEVNODE_V4L:
		return -EINVAL;
	}
}
Esempio n. 16
0
File: isp.c Progetto: Antyks/linux
/*
 * isp_pipeline_enable - Enable streaming on a pipeline
 * @pipe: ISP pipeline
 * @mode: Stream mode (single shot or continuous)
 *
 * Walk the entities chain starting at the pipeline output video node and start
 * all modules in the chain in the given mode.
 *
 * Return 0 if successful, or the return value of the failed video::s_stream
 * operation otherwise.
 */
static int isp_pipeline_enable(struct isp_pipeline *pipe,
			       enum isp_pipeline_stream_state mode)
{
	struct isp_device *isp = pipe->output->isp;
	struct media_entity *entity;
	struct media_pad *pad;
	struct v4l2_subdev *subdev;
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&pipe->lock, flags);
	pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
	spin_unlock_irqrestore(&pipe->lock, flags);

	pipe->do_propagation = false;

	entity = &pipe->output->video.entity;
	while (1) {
		pad = &entity->pads[0];
		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;

		pad = media_entity_remote_source(pad);
		if (pad == NULL ||
		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;

		entity = pad->entity;
		subdev = media_entity_to_v4l2_subdev(entity);

		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return ret;

		if (subdev == &isp->isp_ccdc.subdev) {
			v4l2_subdev_call(&isp->isp_aewb.subdev, video,
					s_stream, mode);
			v4l2_subdev_call(&isp->isp_af.subdev, video,
					s_stream, mode);
			v4l2_subdev_call(&isp->isp_hist.subdev, video,
					s_stream, mode);
			pipe->do_propagation = true;
		}
	}

	/* Frame number propagation. In continuous streaming mode the number
	 * is incremented in the frame start ISR. In mem-to-mem mode
	 * singleshot is used and frame start IRQs are not available.
	 * Thus we have to increment the number here.
	 */
	if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT)
		atomic_inc(&pipe->frame_number);

	return 0;
}
Esempio n. 17
0
/*
* isp_subdev_link_setup - Setup isp subdev connections
* @entity: ispsubdev media entity
* @local: Pad at the local end of the link
* @remote: Pad at the remote end of the link
* @flags: Link flags
*
* return -EINVAL or zero on success
*/
static int isp_subdev_link_setup(struct media_entity *entity,
                                 const struct media_pad *local,
                                 const struct media_pad *remote, u32 flags)
{
    struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
    struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
    struct atomisp_device *isp = isp_sd->isp;

    switch (local->index | media_entity_type(remote->entity)) {
    case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
        /* Read from the sensor CSI2-4p or CSI2-1p. */
        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
            isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
            break;
        }

        if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE)
            return -EBUSY;

        if (remote->entity == &isp->csi2_4p.subdev.entity)
            isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_4P;
        else if (remote->entity == &isp->csi2_1p.subdev.entity)
            isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_1P;
        else
            isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_4P;

        break;

    case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_T_DEVNODE:
        /* read from memory */
        if (flags & MEDIA_LNK_FL_ENABLED) {
            if (isp_sd->input == ATOMISP_SUBDEV_INPUT_CSI2_4P
                    || isp_sd->input == ATOMISP_SUBDEV_INPUT_CSI2_1P)
                return -EBUSY;
            isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY;
        } else {
            if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY)
                isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
        }
        break;

    case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_T_DEVNODE:
        /* always write to memory */
        break;

    case ATOMISP_SUBDEV_PAD_SOURCE_MO | MEDIA_ENT_T_DEVNODE:
        /* always write to memory */
        break;

    default:
        return -EINVAL;
    }

    return 0;
}
Esempio n. 18
0
/*
 * ipipeif_link_setup - Setup IPIPEIF connections
 * @entity: IPIPEIF media entity
 * @local: Pad at the local end of the link
 * @remote: Pad at the remote end of the link
 * @flags: Link flags
 *
 * return -EINVAL or zero on success
 */
static int ipipeif_link_setup(struct media_entity *entity,
			   const struct media_pad *local,
			   const struct media_pad *remote, u32 flags)
{
	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
	struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
	struct iss_device *iss = to_iss_device(ipipeif);

	switch (local->index | media_entity_type(remote->entity)) {
	case IPIPEIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
		/* Read from the sensor CSI2a or CSI2b. */
		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
			ipipeif->input = IPIPEIF_INPUT_NONE;
			break;
		}

		if (ipipeif->input != IPIPEIF_INPUT_NONE)
			return -EBUSY;

		if (remote->entity == &iss->csi2a.subdev.entity)
			ipipeif->input = IPIPEIF_INPUT_CSI2A;
		else if (remote->entity == &iss->csi2b.subdev.entity)
			ipipeif->input = IPIPEIF_INPUT_CSI2B;

		break;

	case IPIPEIF_PAD_SOURCE_ISIF_SF | MEDIA_ENT_T_DEVNODE:
		/* Write to memory */
		if (flags & MEDIA_LNK_FL_ENABLED) {
			if (ipipeif->output & ~IPIPEIF_OUTPUT_MEMORY)
				return -EBUSY;
			ipipeif->output |= IPIPEIF_OUTPUT_MEMORY;
		} else {
			ipipeif->output &= ~IPIPEIF_OUTPUT_MEMORY;
		}
		break;

	case IPIPEIF_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
		/* Send to IPIPE/RESIZER */
		if (flags & MEDIA_LNK_FL_ENABLED) {
			if (ipipeif->output & ~IPIPEIF_OUTPUT_VP)
				return -EBUSY;
			ipipeif->output |= IPIPEIF_OUTPUT_VP;
		} else {
			ipipeif->output &= ~IPIPEIF_OUTPUT_VP;
		}
		break;

	default:
		return -EINVAL;
	}

	return 0;
}
Esempio n. 19
0
/*
 * ccdc_link_setup - Setup CCDC connections
 * @entity: CCDC media entity
 * @local: Pad at the local end of the link
 * @remote: Pad at the remote end of the link
 * @flags: Link flags
 *
 * return -EINVAL or zero on success
 */
static int resizer_link_setup(struct media_entity *entity,
			   const struct media_pad *local,
			   const struct media_pad *remote, u32 flags)
{

	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
	struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);

	switch (local->index | media_entity_type(remote->entity)) {
	case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
		/* Read from previewer - continous mode */
		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
			reset_resizer_channel_mode(resizer);
			resizer->input = RESIZER_INPUT_NONE;
			break;
		}

		if (resizer->input != RESIZER_INPUT_NONE)
			return -EBUSY;

		resizer->input = RESIZER_INPUT_PREVIEWER;

		/* TODO: need 2 handle this */
		set_resizer_channel_cont_mode(resizer);

		break;

	case RESIZER_PAD_SINK | MEDIA_ENT_T_DEVNODE:
		/* Read from memory - single shot mode*/
		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
			reset_resizer_channel_mode(resizer);
			resizer->input = RESIZER_INPUT_NONE;
			break;
		}

		if (set_resizer_channel_ss_mode(resizer))
			return -EINVAL;

		resizer->input = RESIZER_INPUT_MEMORY;
		break;
	case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
		/* Write to memory */
		if (flags & MEDIA_LNK_FL_ENABLED)
			resizer->output = RESIZER_OUPUT_MEMORY;
		else
			resizer->output = RESIZER_OUTPUT_NONE;

		break;
	default:
		return -EINVAL;
	}

	return 0;
}
Esempio n. 20
0
/**
 * fimc_pipeline_validate - check for formats inconsistencies
 *                          between source and sink pad of each link
 *
 * Return 0 if all formats match or -EPIPE otherwise.
 */
static int fimc_pipeline_validate(struct fimc_dev *fimc)
{
	struct v4l2_subdev_format sink_fmt, src_fmt;
	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
	struct v4l2_subdev *sd;
	struct media_pad *pad;
	int ret;

	/* Start with the video capture node pad */
	pad = media_entity_remote_source(&vid_cap->vd_pad);
	if (pad == NULL)
		return -EPIPE;
	/* FIMC.{N} subdevice */
	sd = media_entity_to_v4l2_subdev(pad->entity);

	while (1) {
		/* Retrieve format at the sink pad */
		pad = &sd->entity.pads[0];
		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;
		/* Don't call FIMC subdev operation to avoid nested locking */
		if (sd == fimc->vid_cap.subdev) {
			struct fimc_frame *ff = &vid_cap->ctx->s_frame;
			sink_fmt.format.width = ff->f_width;
			sink_fmt.format.height = ff->f_height;
			sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0;
		} else {
			sink_fmt.pad = pad->index;
			sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
			ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
			if (ret < 0 && ret != -ENOIOCTLCMD)
				return -EPIPE;
		}
		/* Retrieve format at the source pad */
		pad = media_entity_remote_source(pad);
		if (pad == NULL ||
		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;

		sd = media_entity_to_v4l2_subdev(pad->entity);
		src_fmt.pad = pad->index;
		src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return -EPIPE;

		if (src_fmt.format.width != sink_fmt.format.width ||
		    src_fmt.format.height != sink_fmt.format.height ||
		    src_fmt.format.code != sink_fmt.format.code)
			return -EPIPE;
	}
	return 0;
}
Esempio n. 21
0
/* Locking: called with entity->parent->graph_mutex mutex held. */
static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable)
{
	struct media_entity *entity_err = entity;
	struct media_entity_graph graph;
	int ret;

	/*
	 * Walk current graph and call the pipeline open/close routine for each
	 * opened video node that belongs to the graph of entities connected
	 * through active links. This is needed as we cannot power on/off the
	 * subdevs in random order.
	 */
	media_entity_graph_walk_start(&graph, entity);

	while ((entity = media_entity_graph_walk_next(&graph))) {
		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
			continue;

		ret  = __fimc_md_modify_pipeline(entity, enable);

		if (ret < 0)
			goto err;
	}

	return 0;
 err:
	media_entity_graph_walk_start(&graph, entity_err);

	while ((entity_err = media_entity_graph_walk_next(&graph))) {
		if (media_entity_type(entity_err) != MEDIA_ENT_T_DEVNODE)
			continue;

		__fimc_md_modify_pipeline(entity_err, !enable);

		if (entity_err == entity)
			break;
	}

	return ret;
}
Esempio n. 22
0
/**
 * fimc_pipeline_prepare - update pipeline information with subdevice pointers
 * @me: media entity terminating the pipeline
 *
 * Caller holds the graph mutex.
 */
static void fimc_pipeline_prepare(struct fimc_pipeline *p,
				  struct media_entity *me)
{
	struct v4l2_subdev *sd;
	int i;

	for (i = 0; i < IDX_MAX; i++)
		p->subdevs[i] = NULL;

	while (1) {
		struct media_pad *pad = NULL;

		/* Find remote source pad */
		for (i = 0; i < me->num_pads; i++) {
			struct media_pad *spad = &me->pads[i];
			if (!(spad->flags & MEDIA_PAD_FL_SINK))
				continue;
			pad = media_entity_remote_source(spad);
			if (pad)
				break;
		}

		if (pad == NULL ||
		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;
		sd = media_entity_to_v4l2_subdev(pad->entity);

		switch (sd->grp_id) {
		case GRP_ID_FIMC_IS_SENSOR:
		case GRP_ID_SENSOR:
			p->subdevs[IDX_SENSOR] = sd;
			break;
		case GRP_ID_CSIS:
			p->subdevs[IDX_CSIS] = sd;
			break;
		case GRP_ID_FLITE:
			p->subdevs[IDX_FLITE] = sd;
			break;
		case GRP_ID_FIMC:
			/* No need to control FIMC subdev through subdev ops */
			break;
		case GRP_ID_FIMC_IS:
			p->subdevs[IDX_IS_ISP] = sd;
			break;
		default:
			break;
		}
		me = &sd->entity;
		if (me->num_pads == 1)
			break;
	}
}
Esempio n. 23
0
/**
 * fimc_pipeline_prepare - update pipeline information with subdevice pointers
 * @fimc: fimc device terminating the pipeline
 *
 * Caller holds the graph mutex.
 */
void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me)
{
	struct media_pad *pad = &me->pads[0];
	struct v4l2_subdev *sd;
	int i;

	for (i = 0; i < IDX_MAX; i++)
		p->subdevs[i] = NULL;

	if (gfmd->fimc[0]->vid_cap.use_isp) {
		p->subdevs[IDX_SENSOR] = gfmd->fimc[0]->vid_cap.isp_subdev;
		p->subdevs[IDX_CSIS]  = gfmd->fimc[0]->vid_cap.mipi_subdev;
		p->subdevs[IDX_FLITE] =	gfmd->fimc[0]->vid_cap.flite_subdev;
		gfmd->fimc[0]->vid_cap.is.sd = \
			gfmd->fimc[0]->vid_cap.isp_subdev;
		return;
	}
	while (1) {
		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;

		/* source pad */
		pad = media_entity_remote_source(pad);
		if (pad == NULL ||
		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;

		sd = media_entity_to_v4l2_subdev(pad->entity);

		switch (sd->grp_id) {
		case SENSOR_GROUP_ID:
			p->subdevs[IDX_SENSOR] = sd;
			break;
		case CSIS_GROUP_ID:
			p->subdevs[IDX_CSIS] = sd;
			break;
		case FLITE_GROUP_ID:
			p->subdevs[IDX_FLITE] = sd;
			break;
		case FIMC_GROUP_ID:
			/* No need to control FIMC subdev through subdev ops */
			break;
		default:
			pr_warn("%s: Unknown subdev grp_id: %#x\n",
				__func__, sd->grp_id);
		}
		/* sink pad */
		pad = &sd->entity.pads[0];
	}
}
Esempio n. 24
0
File: isp.c Progetto: Antyks/linux
/*
 * isp_pipeline_pm_use_count - Count the number of users of a pipeline
 * @entity: The entity
 *
 * Return the total number of users of all video device nodes in the pipeline.
 */
static int isp_pipeline_pm_use_count(struct media_entity *entity)
{
	struct media_entity_graph graph;
	int use = 0;

	media_entity_graph_walk_start(&graph, entity);

	while ((entity = media_entity_graph_walk_next(&graph))) {
		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
			use += entity->use_count;
	}

	return use;
}
Esempio n. 25
0
static struct v4l2_subdev *gsc_cap_remote_subdev(struct gsc_dev *gsc, u32 *pad)
{
	struct media_pad *remote;

	remote = media_entity_remote_source(&gsc->cap.vd_pad);

	if (remote == NULL ||
	    media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
		return NULL;

	if (pad)
		*pad = remote->index;

	return media_entity_to_v4l2_subdev(remote->entity);
}
Esempio n. 26
0
static struct v4l2_subdev *
xvip_dma_remote_subdev(struct media_pad *local, u32 *pad)
{
	struct media_pad *remote;

	remote = media_entity_remote_pad(local);
	if (remote == NULL ||
	    media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
		return NULL;

	if (pad)
		*pad = remote->index;

	return media_entity_to_v4l2_subdev(remote->entity);
}
Esempio n. 27
0
static int gsc_capture_link_setup(struct media_entity *entity,
				  const struct media_pad *local,
				  const struct media_pad *remote, u32 flags)
{
	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
	struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
	struct gsc_capture_device *cap = &gsc->cap;

	switch (local->index | media_entity_type(remote->entity)) {
	case GSC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
		if (flags & MEDIA_LNK_FL_ENABLED) {
			gsc_dbg("local to gsc-subdev link enable");
			if (cap->input != 0)
				return -EBUSY;
			/* Write-Back link enabled */
			if (!strcmp(remote->entity->name, FIMD_MODULE_NAME)) {
				gsc->cap.sd_disp =
					media_entity_to_v4l2_subdev(remote->entity);
				gsc->cap.sd_disp->grp_id = FIMD_GRP_ID;
				cap->ctx->in_path = GSC_WRITEBACK;
				cap->input = GSC_IN_FIMD_WRITEBACK;
			} else if (remote->index == FLITE_PAD_SOURCE_PREV) {
				cap->ctx->in_path = GSC_CAMERA;
				cap->input = GSC_IN_FLITE_PREVIEW;
			} else {
				cap->ctx->in_path = GSC_CAMERA;
				cap->input = GSC_IN_FLITE_CAMCORDING;
			}
		} else {
			if (cap->input == GSC_IN_FIMD_WRITEBACK)
				gsc->pipeline.disp = NULL;
			else if ((cap->input == GSC_IN_FLITE_PREVIEW) ||
				(cap->input == GSC_IN_FLITE_CAMCORDING))
				gsc->pipeline.flite = NULL;
			gsc_dbg("local to gsc-subdev link disable");
			cap->input = GSC_IN_NONE;
		}
		break;
	case GSC_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
		if (flags & MEDIA_LNK_FL_ENABLED)
			gsc_dbg("gsc-subdev to gsc-video link enable");
		else
			gsc_dbg("gsc-subdev to gsc-video link disable");
		break;
	}

	return 0;
}
Esempio n. 28
0
/* Capture subdev media entity operations */
static int fimc_lite_link_setup(struct media_entity *entity,
				const struct media_pad *local,
				const struct media_pad *remote, u32 flags)
{
	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
	unsigned int remote_ent_type = media_entity_type(remote->entity);

	if (WARN_ON(fimc == NULL))
		return 0;

	v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x",
		 __func__, local->entity->name, remote->entity->name,
		 flags, fimc->source_subdev_grp_id);

	switch (local->index) {
	case FIMC_SD_PAD_SINK:
		if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV)
			return -EINVAL;

		if (flags & MEDIA_LNK_FL_ENABLED) {
			if (fimc->source_subdev_grp_id != 0)
				return -EBUSY;
			fimc->source_subdev_grp_id = sd->grp_id;
			return 0;
		}

		fimc->source_subdev_grp_id = 0;
		break;

	case FIMC_SD_PAD_SOURCE:
		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
			fimc->out_path = FIMC_IO_NONE;
			return 0;
		}
		if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
			fimc->out_path = FIMC_IO_ISP;
		else
			fimc->out_path = FIMC_IO_DMA;
		break;

	default:
		v4l2_err(sd, "Invalid pad index\n");
		return -EINVAL;
	}

	return 0;
}
static struct v4l2_subdev *
isp_video_remote_subdev(struct isp_video *video, u32 *pad)
{
    struct media_pad *remote;

    remote = media_entity_remote_source(&video->pad);

    if (remote == NULL ||
            media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
        return NULL;

    if (pad)
        *pad = remote->index;

    return media_entity_to_v4l2_subdev(remote->entity);
}
Esempio n. 30
0
/*
 * iss_pipeline_enable - Enable streaming on a pipeline
 * @pipe: ISS pipeline
 * @mode: Stream mode (single shot or continuous)
 *
 * Walk the entities chain starting at the pipeline output video node and start
 * all modules in the chain in the given mode.
 *
 * Return 0 if successful, or the return value of the failed video::s_stream
 * operation otherwise.
 */
static int iss_pipeline_enable(struct iss_pipeline *pipe,
			       enum iss_pipeline_stream_state mode)
{
	struct iss_device *iss = pipe->output->iss;
	struct media_entity *entity;
	struct media_pad *pad;
	struct v4l2_subdev *subdev;
	unsigned long flags;
	int ret;

	/* If one of the entities in the pipeline has crashed it will not work
	 * properly. Refuse to start streaming in that case. This check must be
	 * performed before the loop below to avoid starting entities if the
	 * pipeline won't start anyway (those entities would then likely fail to
	 * stop, making the problem worse).
	 */
	if (pipe->entities & iss->crashed)
		return -EIO;

	spin_lock_irqsave(&pipe->lock, flags);
	pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
	spin_unlock_irqrestore(&pipe->lock, flags);

	pipe->do_propagation = false;

	entity = &pipe->output->video.entity;
	while (1) {
		pad = &entity->pads[0];
		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;

		pad = media_entity_remote_pad(pad);
		if (pad == NULL ||
		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;

		entity = pad->entity;
		subdev = media_entity_to_v4l2_subdev(entity);

		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return ret;
	}
	iss_print_status(pipe->output->iss);
	return 0;
}