static int wfd_close(struct file *filp)
{
	struct wfd_inst *inst;
	struct wfd_device *wfd_dev;
	int rc = 0;
	int k;
	unsigned long flags;
	wfd_dev = video_drvdata(filp);
	WFD_MSG_DBG("wfd_close: E\n");
	inst = filp->private_data;
	if (inst) {
		wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
				MDP_CLOSE, (void *)inst->mdp_inst);
		if (rc)
			WFD_MSG_ERR("Failed to CLOSE mdp subdevice: %d\n", rc);
		spin_lock_irqsave(&inst->inst_lock, flags);
		if (inst->minfo) {
			for (k = 0; k < inst->buf_count; ++k)
				kfree(inst->minfo[k]);
		}
		kfree(inst->minfo);
		inst->minfo = NULL;
		spin_unlock_irqrestore(&inst->inst_lock, flags);
		kfree(inst);
	}
	WFD_MSG_DBG("wfd_close: X\n");
	return 0;
}
static int mdp_output_thread(void *data)
{
	int rc = 0;
	struct file *filp = (struct file *)data;
	struct wfd_inst *inst = filp->private_data;
	struct wfd_device *wfd_dev =
		(struct wfd_device *)video_drvdata(filp);
	struct vb2_buffer *vbuf = NULL;
	struct mdp_buf_info obuf = {inst->mdp_inst, vbuf, 0, 0};
	while (!kthread_should_stop()) {
		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev,
			core, ioctl, MDP_DQ_BUFFER, (void *)&obuf);

		if (rc) {
			WFD_MSG_ERR("Either streamoff called or"
						" MDP REPORTED ERROR\n");
			break;
		} else
			WFD_MSG_DBG("Dequeued buffer successfully\n");

		vbuf = obuf.b;
		vb2_buffer_done(vbuf,
			rc ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
	}
	WFD_MSG_DBG("Exiting the thread\n");
	return rc;
}
static int wfd_open(struct file *filp)
{
	int rc = 0;
	struct wfd_inst *inst;
	struct wfd_device *wfd_dev;
	WFD_MSG_DBG("wfd_open: E\n");
	inst = kzalloc(sizeof(struct wfd_inst), GFP_KERNEL);
	if (!inst) {
		WFD_MSG_ERR("Could not allocate memory for "
			"wfd instance\n");
		return -ENOMEM;
	}
	spin_lock_init(&inst->inst_lock);
	spin_lock_init(&inst->buflock);
	wfd_dev = video_drvdata(filp);
	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
				(void *)&inst->mdp_inst);
	if (rc) {
		WFD_MSG_ERR("Failed to open mdp subdevice: %d\n", rc);
		goto err_mdp_open;
	}

	videobuf2_queue_pmem_contig_init(&inst->vid_bufq,
				V4L2_BUF_TYPE_VIDEO_CAPTURE,
				&wfd_vidbuf_ops,
				sizeof(struct wfd_vid_buffer),
				filp);  /*TODO: Check if it needs to be freed*/
	wfd_set_default_properties(inst);
	filp->private_data = inst;
	WFD_MSG_DBG("wfd_open: X\n");
	return rc;
err_mdp_open:
	kfree(inst);
	return rc;
}
static int wfdioc_querycap(struct file *filp, void *fh,
		struct v4l2_capability *cap) {
	WFD_MSG_DBG("wfdioc_querycap: E\n");
	memset(cap, 0, sizeof(struct v4l2_capability));
	strlcpy(cap->driver, "wifi-display", sizeof(cap->driver));
	strlcpy(cap->card, "msm", sizeof(cap->card));
	cap->version = WFD_VERSION;
	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
	WFD_MSG_DBG("wfdioc_querycap: X\n");
	return 0;
}
static int __devinit __wfd_probe(struct platform_device *pdev)
{
	int rc = 0;
	struct wfd_device *wfd_dev;
	WFD_MSG_DBG("__wfd_probe: E\n");
	wfd_dev = kzalloc(sizeof(*wfd_dev), GFP_KERNEL);  /*TODO: Free it*/
	if (!wfd_dev) {
		WFD_MSG_ERR("Could not allocate memory for "
				"wfd device\n");
		return -ENOMEM;
	}
	pdev->dev.platform_data = (void *) wfd_dev;
	rc = v4l2_device_register(&pdev->dev, &wfd_dev->v4l2_dev);
	if (rc) {
		WFD_MSG_ERR("Failed to register the video device\n");
		goto err_v4l2_registration;
	}
	wfd_dev->pvdev = video_device_alloc();
	if (!wfd_dev->pvdev) {
		WFD_MSG_ERR("Failed to allocate video device\n");
		goto err_video_device_alloc;
	}

	wfd_dev->pvdev->release = release_video_device;
	wfd_dev->pvdev->fops = &g_wfd_fops;
	wfd_dev->pvdev->ioctl_ops = &g_wfd_ioctl_ops;

	rc = video_register_device(wfd_dev->pvdev, VFL_TYPE_GRABBER, -1);
	if (rc) {
		WFD_MSG_ERR("Failed to register the device\n");
		goto err_video_register_device;
	}
	video_set_drvdata(wfd_dev->pvdev, wfd_dev);

	v4l2_subdev_init(&wfd_dev->mdp_sdev, &mdp_subdev_ops);
	strncpy(wfd_dev->mdp_sdev.name, "wfd-mdp", V4L2_SUBDEV_NAME_SIZE);
	rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
						&wfd_dev->mdp_sdev);
	if (rc) {
		WFD_MSG_ERR("Failed to register mdp subdevice: %d\n", rc);
		goto err_mdp_register_subdev;
	}
	WFD_MSG_DBG("__wfd_probe: X\n");
	return rc;
err_mdp_register_subdev:
	video_unregister_device(wfd_dev->pvdev);
err_video_register_device:
	video_device_release(wfd_dev->pvdev);
err_video_device_alloc:
	v4l2_device_unregister(&wfd_dev->v4l2_dev);
err_v4l2_registration:
	kfree(wfd_dev);
	return rc;
}
static int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
{
	int rc = 0;
	struct mdp_buf_info *binfo = arg;
	struct msmfb_data fbdata;
	struct mdp_instance *inst;
	if (!binfo || !binfo->inst || !binfo->cookie) {
		WFD_MSG_ERR("Invalid argument\n");
		return -EINVAL;
	}
	inst = binfo->inst;
	fbdata.offset = binfo->offset;
	fbdata.memory_id = binfo->fd;
	fbdata.iova = binfo->paddr;
	fbdata.id = 0;
	fbdata.flags = 0;
	fbdata.priv = (uint32_t)binfo->cookie;

	WFD_MSG_DBG("queue buffer to mdp with offset = %u, fd = %u, "\
			"priv = %p, iova = %p\n",
			fbdata.offset, fbdata.memory_id,
			(void *)fbdata.priv, (void *)fbdata.iova);
	rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);

	if (rc)
		WFD_MSG_ERR("Failed to queue buffer\n");
	return rc;
}
static int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
{
	static int foo;
	int rc = 0;
	struct mdp_buf_info *binfo = arg;
	struct mdp_instance *inst = NULL;
	struct mdp_buf_queue *new_entry = NULL;

	if (!binfo || !binfo->inst || !binfo->cookie) {
		WFD_MSG_ERR("Invalid argument\n");
		return -EINVAL;
	}

	inst = binfo->inst;
	new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
	if (!new_entry)
		return -ENOMEM;

	new_entry->mdp_buf_info = *binfo;
	if (binfo->kvaddr)
		memset((void *)binfo->kvaddr, foo++, 1024);


	mutex_lock(&inst->mutex);
	list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
	mutex_unlock(&inst->mutex);

	WFD_MSG_DBG("Queue %p with cookie %p\n",
			(void *)binfo->paddr, (void *)binfo->cookie);
	return rc;
}
static int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
{
	struct mdp_buf_info *binfo = arg;
	struct mdp_buf_queue *head = NULL;
	struct mdp_instance *inst = NULL;

	inst = binfo->inst;

	while (head == NULL) {
		mutex_lock(&inst->mutex);
		if (!list_empty(&inst->mdp_bufs.node))
			head = list_first_entry(&inst->mdp_bufs.node,
					struct mdp_buf_queue, node);
		mutex_unlock(&inst->mutex);
	}

	if (head == NULL)
		return -ENOBUFS;

	mutex_lock(&inst->mutex);
	list_del(&head->node);
	mutex_unlock(&inst->mutex);

	*binfo = head->mdp_buf_info;
	WFD_MSG_DBG("Dequeue %p with cookie %p\n",
		(void *)binfo->paddr, (void *)binfo->cookie);
	return 0;

}
static int __init wfd_init(void)
{
	int rc = 0;
	WFD_MSG_DBG("Calling init function of wfd driver\n");
	rc = platform_driver_register(&wfd_driver);
	if (rc) {
		WFD_MSG_ERR("failed to load the driver\n");
		goto err_platform_registration;
	}
err_platform_registration:
	return rc;
}
static int wfd_vidbuf_queue_setup(struct vb2_queue *q,
		unsigned int *num_buffers, unsigned int *num_planes,
		unsigned long sizes[], void *alloc_ctxs[])
{
	WFD_MSG_DBG("In %s\n", __func__);

	if (num_buffers == NULL || num_planes == NULL)
		return -EINVAL;

	*num_planes = 1;
	/*MDP outputs in RGB for now;i
	 * make sure it's smaller than VIDEO_MAX_PLANES*/
	sizes[0] = 800*480*2;

	return 0;
}
Exemple #11
0
int mdp_stop(struct v4l2_subdev *sd, void *arg)
{
	struct mdp_instance *inst = arg;
	int rc = 0;
	struct fb_info *fbi = NULL;
	if (inst) {
		rc = msm_fb_writeback_stop(inst->mdp);
		if (rc) {
			WFD_MSG_ERR("Failed to stop writeback mode\n");
			return rc;
		}
		fbi = (struct fb_info *)inst->mdp;
		switch_set_state(&inst->sdev, false);
		WFD_MSG_DBG("wfd state switched to %d\n", inst->sdev.state);
	}
	return 0;
}
static int __devexit __wfd_remove(struct platform_device *pdev)
{
	struct wfd_device *wfd_dev;
	wfd_dev = (struct wfd_device *)pdev->dev.platform_data;

	WFD_MSG_DBG("Inside wfd_remove\n");
	if (!wfd_dev) {
		WFD_MSG_ERR("Error removing WFD device");
		return -ENODEV;
	}

	v4l2_device_unregister_subdev(&wfd_dev->mdp_sdev);
	video_unregister_device(wfd_dev->pvdev);
	video_device_release(wfd_dev->pvdev);
	v4l2_device_unregister(&wfd_dev->v4l2_dev);
	kfree(wfd_dev);
	return 0;
}
int wfd_stats_deinit(struct wfd_stats *stats)
{
	WFD_MSG_DBG("Latencies: avg enc. latency %d",
			stats->enc_avg_latency);
	
	if (stats->d_parent)
		debugfs_remove_recursive(stats->d_parent);

	stats->d_parent =
	stats->d_v4l2_buf_count =
	stats->d_mdp_buf_count =
	stats->d_vsg_buf_count =
	stats->d_enc_buf_count =
	stats->d_frames_encoded =
	stats->d_mdp_updates =
	stats->d_enc_avg_latency = NULL;

	return 0;
}
void wfd_vidbuf_buf_cleanup(struct vb2_buffer *vb)
{
	int rc = 0;
	struct vb2_queue *q = vb->vb2_queue;
	struct file *priv_data = (struct file *)(q->drv_priv);
	struct wfd_device *wfd_dev =
		(struct wfd_device *)video_drvdata(priv_data);
	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
	struct mdp_buf_info buf = {
					inst->mdp_inst,
					vb,
					inst->minfo[vb->v4l2_buf.index]->fd,
					inst->minfo[vb->v4l2_buf.index]->offset
					};
	WFD_MSG_DBG("Releasing buffer\n");
	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
			 MDP_RELEASE_BUF, (void *)&buf);
	if (rc)
		WFD_MSG_ERR("Failed to release the buffer\n");
}
static int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
{
	int rc = 0;
	struct mdp_buf_info *obuf = arg;
	struct msmfb_data fbdata;
	struct mdp_instance *inst;
	if (!arg) {
		WFD_MSG_ERR("Invalid argument\n");
		return -EINVAL;
	}

	inst = obuf->inst;
	fbdata.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
	rc = msm_fb_writeback_dequeue_buffer(inst->mdp, &fbdata);
	if (rc) {
		WFD_MSG_ERR("Failed to dequeue buffer\n");
		return rc;
	}
	WFD_MSG_DBG("dequeue buf from mdp with priv = %u\n",
			fbdata.priv);
	obuf->cookie = (void *)fbdata.priv;
	return rc;
}
Exemple #16
0
int mdp_start(struct v4l2_subdev *sd, void *arg)
{
	struct mdp_instance *inst = arg;
	int rc = 0;
	struct fb_info *fbi = NULL;
	if (inst) {
		rc = msm_fb_writeback_start(inst->mdp);
		if (rc) {
			WFD_MSG_ERR("Failed to start MDP mode\n");
			goto exit;
		}
		fbi = msm_fb_get_writeback_fb();
		if (!fbi) {
			WFD_MSG_ERR("Failed to acquire mdp instance\n");
			rc = -ENODEV;
			goto exit;
		}
		switch_set_state(&inst->sdev, true);
		WFD_MSG_DBG("wfd state switched to %d\n", inst->sdev.state);
	}
exit:
	return rc;
}
static int wfdioc_streamoff(struct file *filp, void *fh,
		enum v4l2_buf_type i)
{
	struct wfd_inst *inst = filp->private_data;
	unsigned long flags;
	spin_lock_irqsave(&inst->inst_lock, flags);
	if (inst->streamoff) {
		WFD_MSG_ERR("Module is already in streamoff state\n");
		spin_unlock_irqrestore(&inst->inst_lock, flags);
		return -EINVAL;
	}
	inst->streamoff = true;
	spin_unlock_irqrestore(&inst->inst_lock, flags);
	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
		WFD_MSG_ERR("stream off for buffer type = %d is not "
			"supported.\n", i);
		return -EINVAL;
	}
	WFD_MSG_DBG("Calling videobuf_streamoff\n");
	vb2_streamoff(&inst->vid_bufq, i);
	vb2_queue_release(&inst->vid_bufq);
	kthread_stop(inst->mdp_task);
	return 0;
}
static void __exit wfd_exit(void)
{
	WFD_MSG_DBG("wfd_exit: X\n");
	platform_driver_unregister(&wfd_driver);
}