Hi Helen,

Please see my comments below.

Helen Koike wrote:
> On 2017-01-25 11:03 AM, Sakari Ailus wrote:
...
>>> +     * the videobuf2 framework will allocate this struct based on
>>> +     * buf_struct_size and use the first sizeof(struct vb2_buffer)
>>> bytes of
>>> +     * memory as a vb2_buffer
>>> +     */
>>> +    struct vb2_v4l2_buffer vb2;
>>> +    struct list_head list;
>>> +};
>>> +
>>> +static int vimc_cap_querycap(struct file *file, void *priv,
>>> +                 struct v4l2_capability *cap)
>>> +{
>>> +    struct vimc_cap_device *vcap = video_drvdata(file);
>>> +
>>> +    strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
>>> +    strlcpy(cap->card, KBUILD_MODNAME, sizeof(cap->card));
>>> +    snprintf(cap->bus_info, sizeof(cap->bus_info),
>>> +         "platform:%s", vcap->v4l2_dev->name);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int vimc_cap_enum_input(struct file *file, void *priv,
>>> +                   struct v4l2_input *i)
>>> +{
>>> +    /* We only have one input */
>>> +    if (i->index > 0)
>>> +        return -EINVAL;
>>> +
>>> +    i->type = V4L2_INPUT_TYPE_CAMERA;
>>> +    strlcpy(i->name, "VIMC capture", sizeof(i->name));
>>
>> Isn't this (*INPUT IOCTLs) something that should be handled in a
>> sub-device
>> driver, such as a TV tuner?
> 
> 
> Can the ioctl VIDIOC_ENUMINPUT enumerate no inputs at all? Can I just
> return -EINVAL here in G_INPUT and S_INPUT as well?
> I thought I had to enumerate at least one input, and between
> V4L2_INPUT_TYPE_TUNER and V4L2_INPUT_TYPE_CAMERA, this last
> one seems more appropriated

I don't think other drivers that provide MC interface do this on video
nodes either. The VIMC driver could know what's connected to it, but
generally that's not the case.

> 
> 
>>
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int vimc_cap_g_input(struct file *file, void *priv, unsigned
>>> int *i)
>>> +{
>>> +    /* We only have one input */
>>> +    *i = 0;
>>> +    return 0;
>>> +}
>>> +
>>> +static int vimc_cap_s_input(struct file *file, void *priv, unsigned
>>> int i)
>>> +{
>>> +    /* We only have one input */
>>> +    return i ? -EINVAL : 0;
>>> +}
>>> +
>>> +static int vimc_cap_fmt_vid_cap(struct file *file, void *priv,
>>> +                  struct v4l2_format *f)
>>> +{
>>> +    struct vimc_cap_device *vcap = video_drvdata(file);
>>> +
>>> +    f->fmt.pix = vcap->format;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv,
>>> +                     struct v4l2_fmtdesc *f)
>>> +{
>>> +    struct vimc_cap_device *vcap = video_drvdata(file);
>>> +
>>> +    if (f->index > 0)
>>> +        return -EINVAL;
>>> +
>>> +    /* We only support one format for now */
>>> +    f->pixelformat = vcap->format.pixelformat;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static const struct v4l2_file_operations vimc_cap_fops = {
>>> +    .owner        = THIS_MODULE,
>>> +    .open        = v4l2_fh_open,
>>> +    .release    = vb2_fop_release,
>>> +    .read           = vb2_fop_read,
>>> +    .poll        = vb2_fop_poll,
>>> +    .unlocked_ioctl = video_ioctl2,
>>> +    .mmap           = vb2_fop_mmap,
>>> +};
>>> +
>>> +static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = {
>>> +    .vidioc_querycap = vimc_cap_querycap,
>>> +
>>> +    .vidioc_enum_input = vimc_cap_enum_input,
>>> +    .vidioc_g_input = vimc_cap_g_input,
>>> +    .vidioc_s_input = vimc_cap_s_input,
>>> +
>>> +    .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap,
>>> +    .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap,
>>> +    .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap,
>>> +    .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap,
>>> +
>>> +    .vidioc_reqbufs = vb2_ioctl_reqbufs,
>>> +    .vidioc_create_bufs = vb2_ioctl_create_bufs,
>>> +    .vidioc_querybuf = vb2_ioctl_querybuf,
>>> +    .vidioc_qbuf = vb2_ioctl_qbuf,
>>> +    .vidioc_dqbuf = vb2_ioctl_dqbuf,
>>> +    .vidioc_expbuf = vb2_ioctl_expbuf,
>>> +    .vidioc_streamon = vb2_ioctl_streamon,
>>> +    .vidioc_streamoff = vb2_ioctl_streamoff,
>>> +};
>>> +
>>> +static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,
>>> +                    enum vb2_buffer_state state)
>>> +{
>>> +    struct vimc_cap_buffer *vbuf, *node;
>>> +
>>> +    spin_lock(&vcap->qlock);
>>> +
>>> +    list_for_each_entry_safe(vbuf, node, &vcap->buf_list, list) {
>>> +        vb2_buffer_done(&vbuf->vb2.vb2_buf, state);
>>> +        list_del(&vbuf->list);
>>> +    }
>>> +
>>> +    spin_unlock(&vcap->qlock);
>>> +}
>>> +
>>> +static int vimc_cap_pipeline_s_stream(struct vimc_cap_device *vcap,
>>> int enable)
>>> +{
>>> +    int ret;
>>> +    struct media_pad *pad;
>>> +    struct media_entity *entity;
>>> +    struct v4l2_subdev *sd;
>>> +
>>> +    /* Start the stream in the subdevice direct connected */
>>> +    entity = &vcap->vdev.entity;
>>> +    pad = media_entity_remote_pad(&entity->pads[0]);
>>
>> You could use vcap->vdev.entity.pads here, without assigning to
>> entity. Then
>> entity would only be used to refer to the remove entity at the other
>> end of
>> the link. Up to you.
>>
>>> +
>>> +    /* If we are not connected to any subdev node, it means there is
>>> nothing
>>
>> /*
>>  * Multi line
>>  * comment.
>>  */
>>
>>> +     * to activate on the pipe (e.g. we can be connected with an input
>>> +     * device or we are not connected at all)
>>> +     */
>>> +    if (pad == NULL || !is_media_entity_v4l2_subdev(pad->entity))
>>> +        return 0;
>>> +
>>> +    entity = pad->entity;
>>> +    sd = media_entity_to_v4l2_subdev(entity);
>>
>> And if you used pad->entity here, you could remove the entity variable
>> altogether.
>>
>>> +
>>> +    ret = v4l2_subdev_call(sd, video, s_stream, enable);
>>> +    if (ret && ret != -ENOIOCTLCMD)
>>> +        return ret;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned
>>> int count)
>>> +{
>>> +    struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);
>>> +    struct media_entity *entity;
>>> +    int ret;
>>> +
>>> +    vcap->sequence = 0;
>>> +
>>> +    /* Start the media pipeline */
>>> +    entity = &vcap->vdev.entity;
>>> +    ret = media_entity_pipeline_start(entity, &vcap->pipe);
>>> +    if (ret) {
>>> +        vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
>>> +        return ret;
>>> +    }
>>> +
>>> +    /* Enable streaming from the pipe */
>>> +    ret = vimc_cap_pipeline_s_stream(vcap, 1);
>>> +    if (ret) {
>>> +        vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
>>> +        return ret;
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +/*
>>> + * Stop the stream engine. Any remaining buffers in the stream queue
>>> are
>>> + * dequeued and passed on to the vb2 framework marked as STATE_ERROR.
>>> + */
>>> +static void vimc_cap_stop_streaming(struct vb2_queue *vq)
>>> +{
>>> +    struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);
>>> +
>>> +    /* Disable streaming from the pipe */
>>> +    vimc_cap_pipeline_s_stream(vcap, 0);
>>> +
>>> +    /* Stop the media pipeline */
>>> +    media_entity_pipeline_stop(&vcap->vdev.entity);
>>> +
>>> +    /* Release all active buffers */
>>> +    vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_ERROR);
>>> +}
>>> +
>>> +static void vimc_cap_buf_queue(struct vb2_buffer *vb2_buf)
>>> +{
>>> +    struct vimc_cap_device *vcap =
>>> vb2_get_drv_priv(vb2_buf->vb2_queue);
>>> +    struct vimc_cap_buffer *buf = container_of(vb2_buf,
>>> +                           struct vimc_cap_buffer,
>>> +                           vb2.vb2_buf);
>>> +
>>> +    spin_lock(&vcap->qlock);
>>> +    list_add_tail(&buf->list, &vcap->buf_list);
>>> +    spin_unlock(&vcap->qlock);
>>> +}
>>> +
>>> +static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int
>>> *nbuffers,
>>> +                unsigned int *nplanes, unsigned int sizes[],
>>> +                struct device *alloc_devs[])
>>> +{
>>> +    struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);
>>> +
>>> +    if (*nplanes)
>>> +        return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0;
>>
>> Why? The user could later reconfigure the device to use with a buffer of
>> this size. This might not be a concern for vimc, but the code from
>> example
>> drivers tends to get copied around.
> 
> 
> This first version only support a fixed sizeimage, this will be changed
> in the next patch series where
> I add support for multiple sizes

Sounds good to me. Thanks.

-- 
Kind regards,

Sakari Ailus
sakari.ai...@iki.fi

Reply via email to