Skip to content

Commit

Permalink
[media] vimc: Subdevices as modules
Browse files Browse the repository at this point in the history
Change the core structure for adding subdevices in the topology.
Instead of calling the specific create function for each subdevice,
inject a child platform_device with the driver's name.
Each type of node in the topology (sensor, capture, debayer, scaler)
will register a platform_driver with the corresponding name through the
component subsystem.
Implementing a new subdevice type doesn't require vimc-core to be altered.

This facilitates future implementation of dynamic entities, where
hotpluging an entity in the topology is just a matter of
registering/unregistering a platform_device in the system.
It also facilitates other implementations of different nodes without
touching the core code and remove the need of a header file for each
type of node.

Signed-off-by: Helen Koike <helen.koike@collabora.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
  • Loading branch information
Helen Fornazier authored and Mauro Carvalho Chehab committed Jun 23, 2017
1 parent 535d296 commit 4a29b70
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 388 deletions.
7 changes: 5 additions & 2 deletions drivers/media/platform/vimc/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
vimc-objs := vimc-core.o vimc-capture.o vimc-common.o vimc-sensor.o
vimc-objs := vimc-core.o
vimc_capture-objs := vimc-capture.o
vimc_common-objs := vimc-common.o
vimc_sensor-objs := vimc-sensor.o

obj-$(CONFIG_VIDEO_VIMC) += vimc.o
obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc_sensor.o
99 changes: 69 additions & 30 deletions drivers/media/platform/vimc/vimc-capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@
*
*/

#include <linux/component.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-vmalloc.h>

#include "vimc-capture.h"
#include "vimc-common.h"

#define VIMC_CAP_DRV_NAME "vimc-capture"

struct vimc_cap_device {
struct vimc_ent_device ved;
struct video_device vdev;
struct device *dev;
struct v4l2_pix_format format;
struct vb2_queue queue;
struct list_head buf_list;
Expand Down Expand Up @@ -131,7 +137,7 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,

vimc_cap_try_fmt_vid_cap(file, priv, f);

dev_dbg(vcap->vdev.v4l2_dev->dev, "%s: format update: "
dev_dbg(vcap->dev, "%s: format update: "
"old:%dx%d (0x%x, %d, %d, %d, %d) "
"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name,
/* old */
Expand Down Expand Up @@ -309,8 +315,7 @@ static int vimc_cap_buffer_prepare(struct vb2_buffer *vb)
unsigned long size = vcap->format.sizeimage;

if (vb2_plane_size(vb, 0) < size) {
dev_err(vcap->vdev.v4l2_dev->dev,
"%s: buffer too small (%lu < %lu)\n",
dev_err(vcap->dev, "%s: buffer too small (%lu < %lu)\n",
vcap->vdev.name, vb2_plane_size(vb, 0), size);
return -EINVAL;
}
Expand All @@ -335,8 +340,10 @@ static const struct media_entity_operations vimc_cap_mops = {
.link_validate = vimc_link_validate,
};

static void vimc_cap_destroy(struct vimc_ent_device *ved)
static void vimc_cap_comp_unbind(struct device *comp, struct device *master,
void *master_data)
{
struct vimc_ent_device *ved = dev_get_drvdata(comp);
struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device,
ved);

Expand Down Expand Up @@ -385,42 +392,35 @@ static void vimc_cap_process_frame(struct vimc_ent_device *ved,
vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE);
}

struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,
const char *const name,
u16 num_pads,
const unsigned long *pads_flag)
static int vimc_cap_comp_bind(struct device *comp, struct device *master,
void *master_data)
{
struct v4l2_device *v4l2_dev = master_data;
struct vimc_platform_data *pdata = comp->platform_data;
const struct vimc_pix_map *vpix;
struct vimc_cap_device *vcap;
struct video_device *vdev;
struct vb2_queue *q;
int ret;

/*
* Check entity configuration params
* NOTE: we only support a single sink pad
*/
if (!name || num_pads != 1 || !pads_flag ||
!(pads_flag[0] & MEDIA_PAD_FL_SINK))
return ERR_PTR(-EINVAL);

/* Allocate the vimc_cap_device struct */
vcap = kzalloc(sizeof(*vcap), GFP_KERNEL);
if (!vcap)
return ERR_PTR(-ENOMEM);
return -ENOMEM;

/* Allocate the pads */
vcap->ved.pads = vimc_pads_init(num_pads, pads_flag);
vcap->ved.pads =
vimc_pads_init(1, (const unsigned long[1]) {MEDIA_PAD_FL_SINK});
if (IS_ERR(vcap->ved.pads)) {
ret = PTR_ERR(vcap->ved.pads);
goto err_free_vcap;
}

/* Initialize the media entity */
vcap->vdev.entity.name = name;
vcap->vdev.entity.name = pdata->entity_name;
vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L;
ret = media_entity_pads_init(&vcap->vdev.entity,
num_pads, vcap->ved.pads);
1, vcap->ved.pads);
if (ret)
goto err_clean_pads;

Expand All @@ -441,9 +441,8 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,

ret = vb2_queue_init(q);
if (ret) {
dev_err(vcap->vdev.v4l2_dev->dev,
"%s: vb2 queue init failed (err=%d)\n",
vcap->vdev.name, ret);
dev_err(comp, "%s: vb2 queue init failed (err=%d)\n",
pdata->entity_name, ret);
goto err_clean_m_ent;
}

Expand All @@ -459,10 +458,11 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,
vcap->format.height;

/* Fill the vimc_ent_device struct */
vcap->ved.destroy = vimc_cap_destroy;
vcap->ved.ent = &vcap->vdev.entity;
vcap->ved.process_frame = vimc_cap_process_frame;
vcap->ved.vdev_get_format = vimc_cap_get_format;
dev_set_drvdata(comp, &vcap->ved);
vcap->dev = comp;

/* Initialize the video_device struct */
vdev = &vcap->vdev;
Expand All @@ -475,19 +475,18 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,
vdev->queue = q;
vdev->v4l2_dev = v4l2_dev;
vdev->vfl_dir = VFL_DIR_RX;
strlcpy(vdev->name, name, sizeof(vdev->name));
strlcpy(vdev->name, pdata->entity_name, sizeof(vdev->name));
video_set_drvdata(vdev, &vcap->ved);

/* Register the video_device with the v4l2 and the media framework */
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
if (ret) {
dev_err(vcap->vdev.v4l2_dev->dev,
"%s: video register failed (err=%d)\n",
dev_err(comp, "%s: video register failed (err=%d)\n",
vcap->vdev.name, ret);
goto err_release_queue;
}

return &vcap->ved;
return 0;

err_release_queue:
vb2_queue_release(q);
Expand All @@ -498,5 +497,45 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,
err_free_vcap:
kfree(vcap);

return ERR_PTR(ret);
return ret;
}

static const struct component_ops vimc_cap_comp_ops = {
.bind = vimc_cap_comp_bind,
.unbind = vimc_cap_comp_unbind,
};

static int vimc_cap_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &vimc_cap_comp_ops);
}

static int vimc_cap_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &vimc_cap_comp_ops);

return 0;
}

static struct platform_driver vimc_cap_pdrv = {
.probe = vimc_cap_probe,
.remove = vimc_cap_remove,
.driver = {
.name = VIMC_CAP_DRV_NAME,
},
};

static const struct platform_device_id vimc_cap_driver_ids[] = {
{
.name = VIMC_CAP_DRV_NAME,
},
{ }
};

module_platform_driver(vimc_cap_pdrv);

MODULE_DEVICE_TABLE(platform, vimc_cap_driver_ids);

MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Capture");
MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>");
MODULE_LICENSE("GPL");
28 changes: 0 additions & 28 deletions drivers/media/platform/vimc/vimc-capture.h

This file was deleted.

38 changes: 19 additions & 19 deletions drivers/media/platform/vimc/vimc-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*
*/

#include <linux/init.h>
#include <linux/module.h>

#include "vimc-common.h"

static const struct vimc_pix_map vimc_pix_map_list[] = {
Expand Down Expand Up @@ -151,6 +154,7 @@ const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)

return &vimc_pix_map_list[i];
}
EXPORT_SYMBOL_GPL(vimc_pix_map_by_index);

const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
{
Expand All @@ -162,6 +166,7 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
}
return NULL;
}
EXPORT_SYMBOL_GPL(vimc_pix_map_by_code);

const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
{
Expand All @@ -173,6 +178,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
}
return NULL;
}
EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat);

int vimc_propagate_frame(struct media_pad *src, const void *frame)
{
Expand Down Expand Up @@ -207,6 +213,7 @@ int vimc_propagate_frame(struct media_pad *src, const void *frame)

return 0;
}
EXPORT_SYMBOL_GPL(vimc_propagate_frame);

/* Helper function to allocate and initialize pads */
struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)
Expand All @@ -227,6 +234,7 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)

return pads;
}
EXPORT_SYMBOL_GPL(vimc_pads_init);

int vimc_pipeline_s_stream(struct media_entity *ent, int enable)
{
Expand All @@ -242,14 +250,8 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)
/* Start the stream in the subdevice direct connected */
pad = media_entity_remote_pad(&ent->pads[i]);

/*
* if this is a raw node from vimc-core, then there is
* nothing to activate
* TODO: remove this when there are no more raw nodes in the
* core and return error instead
*/
if (pad->entity->obj_type == MEDIA_ENTITY_TYPE_BASE)
continue;
if (!is_media_entity_v4l2_subdev(pad->entity))
return -EINVAL;

sd = media_entity_to_v4l2_subdev(pad->entity);
ret = v4l2_subdev_call(sd, video, s_stream, enable);
Expand All @@ -259,6 +261,7 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)

return 0;
}
EXPORT_SYMBOL_GPL(vimc_pipeline_s_stream);

static int vimc_get_mbus_format(struct media_pad *pad,
struct v4l2_subdev_format *fmt)
Expand Down Expand Up @@ -301,14 +304,6 @@ int vimc_link_validate(struct media_link *link)
struct v4l2_subdev_format source_fmt, sink_fmt;
int ret;

/*
* if it is a raw node from vimc-core, ignore the link for now
* TODO: remove this when there are no more raw nodes in the
* core and return error instead
*/
if (link->source->entity->obj_type == MEDIA_ENTITY_TYPE_BASE)
return 0;

ret = vimc_get_mbus_format(link->source, &source_fmt);
if (ret)
return ret;
Expand Down Expand Up @@ -378,6 +373,7 @@ int vimc_link_validate(struct media_link *link)

return 0;
}
EXPORT_SYMBOL_GPL(vimc_link_validate);

static const struct media_entity_operations vimc_ent_sd_mops = {
.link_validate = vimc_link_validate,
Expand All @@ -390,8 +386,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
u32 function,
u16 num_pads,
const unsigned long *pads_flag,
const struct v4l2_subdev_ops *sd_ops,
void (*sd_destroy)(struct vimc_ent_device *))
const struct v4l2_subdev_ops *sd_ops)
{
int ret;

Expand All @@ -401,7 +396,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
return PTR_ERR(ved->pads);

/* Fill the vimc_ent_device struct */
ved->destroy = sd_destroy;
ved->ent = &sd->entity;

/* Initialize the subdev */
Expand Down Expand Up @@ -437,10 +431,16 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
vimc_pads_cleanup(ved->pads);
return ret;
}
EXPORT_SYMBOL_GPL(vimc_ent_sd_register);

void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)
{
v4l2_device_unregister_subdev(sd);
media_entity_cleanup(ved->ent);
vimc_pads_cleanup(ved->pads);
}
EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister);

MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Common");
MODULE_AUTHOR("Helen Koike <helen.fornazier@gmail.com>");
MODULE_LICENSE("GPL");
Loading

0 comments on commit 4a29b70

Please sign in to comment.