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; }
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; }
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); }