From: Sylwester Nawrocki <s.nawrocki@samsung.com>
To: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: linux-media@vger.kernel.org,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Hans Verkuil <hverkuil@xs4all.nl>,
linux-sh@vger.kernel.org, Magnus Damm <magnus.damm@gmail.com>,
Sakari Ailus <sakari.ailus@iki.fi>,
Prabhakar Lad <prabhakar.lad@ti.com>
Subject: Re: [PATCH v9 02/20] V4L2: support asynchronous subdevice registration
Date: Mon, 15 Apr 2013 11:57:17 +0000 [thread overview]
Message-ID: <516BEB1D.80105@samsung.com> (raw)
In-Reply-To: <1365781240-16149-3-git-send-email-g.liakhovetski@gmx.de>
Hi Guennadi,
On 04/12/2013 05:40 PM, Guennadi Liakhovetski wrote:
> Currently bridge device drivers register devices for all subdevices
> synchronously, tupically, during their probing. E.g. if an I2C CMOS sensor
> is attached to a video bridge device, the bridge driver will create an I2C
> device and wait for the respective I2C driver to probe. This makes linking
> of devices straight forward, but this approach cannot be used with
> intrinsically asynchronous and unordered device registration systems like
> the Flattened Device Tree. To support such systems this patch adds an
> asynchronous subdevice registration framework to V4L2. To use it respective
> (e.g. I2C) subdevice drivers must register themselves with the framework.
> A bridge driver on the other hand must register notification callbacks,
> that will be called upon various related events.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
>
> v9: addressed Laurent's comments (thanks)
> 1. moved valid hw->bus_type check
> 2. made v4l2_async_unregister() void
> 3. renamed struct v4l2_async_hw_device to struct v4l2_async_hw_info
> 4. merged struct v4l2_async_subdev_list into struct v4l2_subdev
> 5. fixed a typo
> 6. made subdev_num unsigned
>
> drivers/media/v4l2-core/Makefile | 3 +-
> drivers/media/v4l2-core/v4l2-async.c | 284 ++++++++++++++++++++++++++++++++++
> include/media/v4l2-async.h | 99 ++++++++++++
> include/media/v4l2-subdev.h | 10 ++
> 4 files changed, 395 insertions(+), 1 deletions(-)
> create mode 100644 drivers/media/v4l2-core/v4l2-async.c
> create mode 100644 include/media/v4l2-async.h
>
> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
> index 628c630..4c33b8d6 100644
> --- a/drivers/media/v4l2-core/Makefile
> +++ b/drivers/media/v4l2-core/Makefile
> @@ -5,7 +5,8 @@
> tuner-objs := tuner-core.o
>
> videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
> - v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o
> + v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o \
> + v4l2-async.o
> ifeq ($(CONFIG_COMPAT),y)
> videodev-objs += v4l2-compat-ioctl32.o
> endif
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> new file mode 100644
> index 0000000..98db2e0
> --- /dev/null
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -0,0 +1,284 @@
> +/*
> + * V4L2 asynchronous subdevice registration API
> + *
> + * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
[...]
> +static void v4l2_async_cleanup(struct v4l2_async_subdev_list *asdl)
> +{
> + struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
> +
> + v4l2_device_unregister_subdev(sd);
> + /* Subdevice driver will reprobe and put asdl back onto the list */
> + list_del_init(&asdl->list);
> + asdl->asd = NULL;
> + sd->dev = NULL;
> +}
> +
> +static void v4l2_async_unregister(struct v4l2_async_subdev_list *asdl)
> +{
> + struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
> +
> + v4l2_async_cleanup(asdl);
> +
> + /* If we handled USB devices, we'd have to lock the parent too */
> + device_release_driver(sd->dev);
> +}
> +
> +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> + struct v4l2_async_notifier *notifier)
> +{
> + struct v4l2_async_subdev_list *asdl, *tmp;
> + struct v4l2_async_subdev *asd;
> + int i;
> +
> + notifier->v4l2_dev = v4l2_dev;
> + INIT_LIST_HEAD(¬ifier->waiting);
> + INIT_LIST_HEAD(¬ifier->done);
> +
> + for (i = 0; i < notifier->subdev_num; i++) {
> + asd = notifier->subdev[i];
> +
> + switch (asd->hw.bus_type) {
> + case V4L2_ASYNC_BUS_CUSTOM:
> + case V4L2_ASYNC_BUS_PLATFORM:
> + case V4L2_ASYNC_BUS_I2C:
> + break;
> + default:
> + dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
> + "Invalid bus-type %u on %p\n",
> + asd->hw.bus_type, asd);
> + return -EINVAL;
> + }
> + list_add_tail(&asd->list, ¬ifier->waiting);
> + }
> +
> + mutex_lock(&list_lock);
> +
> + /* Keep also completed notifiers on the list */
> + list_add(¬ifier->list, ¬ifier_list);
> +
> + list_for_each_entry_safe(asdl, tmp, &subdev_list, list) {
> + int ret;
> +
> + asd = v4l2_async_belongs(notifier, asdl);
> + if (!asd)
> + continue;
> +
> + ret = v4l2_async_test_notify(notifier, asdl, asd);
> + if (ret < 0) {
> + mutex_unlock(&list_lock);
> + return ret;
> + }
> + }
> +
> + mutex_unlock(&list_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(v4l2_async_notifier_register);
> +
> +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> +{
> + struct v4l2_async_subdev_list *asdl, *tmp;
> + int i = 0;
> + struct device **dev = kcalloc(notifier->subdev_num,
> + sizeof(*dev), GFP_KERNEL);
> + if (!dev)
> + dev_err(notifier->v4l2_dev->dev,
> + "Failed to allocate device cache!\n");
> +
> + mutex_lock(&list_lock);
> +
> + list_del(¬ifier->list);
> +
> + list_for_each_entry_safe(asdl, tmp, ¬ifier->done, list) {
> + if (dev) {
> + struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
> + dev[i++] = get_device(sd->dev);
> + }
> + v4l2_async_unregister(asdl);
Hmm, couldn't we do without the **dev array ? Now when struct v42_subdev has
struct device * embedded in it ?
And if we can't get hold off struct device object is it safe to call
v4l2_async_unregister(), which references it ?
Why is get_device() optional ? Some comment might be useful here.
> +
> + if (notifier->unbind)
> + notifier->unbind(notifier, asdl);
> + }
> +
> + mutex_unlock(&list_lock);
> +
> + if (dev) {
> + while (i--) {
> + if (dev[i] && device_attach(dev[i]) < 0)
> + dev_err(dev[i], "Failed to re-probe to %s\n",
> + dev[i]->driver ? dev[i]->driver->name : "(none)");
Is it safe to reference dev->driver without holding struct device::mutex ?
> + put_device(dev[i]);
> + }
> + kfree(dev);
> + }
> + /*
> + * Don't care about the waiting list, it is initialised and populated
> + * upon notifier registration.
> + */
> +}
> +EXPORT_SYMBOL(v4l2_async_notifier_unregister);
> +
> +int v4l2_async_register_subdev(struct v4l2_subdev *sd)
> +{
> + struct v4l2_async_subdev_list *asdl = &sd->asdl;
> + struct v4l2_async_notifier *notifier;
> +
> + mutex_lock(&list_lock);
> +
> + INIT_LIST_HEAD(&asdl->list);
> +
> + list_for_each_entry(notifier, ¬ifier_list, list) {
> + struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, asdl);
> + if (asd) {
> + int ret = v4l2_async_test_notify(notifier, asdl, asd);
> + mutex_unlock(&list_lock);
> + return ret;
> + }
> + }
> +
> + /* None matched, wait for hot-plugging */
> + list_add(&asdl->list, &subdev_list);
> +
> + mutex_unlock(&list_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(v4l2_async_register_subdev);
> +
> +void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
> +{
> + struct v4l2_async_subdev_list *asdl = &sd->asdl;
> + struct v4l2_async_notifier *notifier = asdl->notifier;
> + struct device *dev;
This variable appears unused, except a single assignment below.
> + if (!asdl->asd) {
> + if (!list_empty(&asdl->list))
> + v4l2_async_cleanup(asdl);
> + return;
> + }
> +
> + mutex_lock(&list_lock);
> +
> + dev = sd->dev;
> + list_add(&asdl->asd->list, ¬ifier->waiting);
> +
> + v4l2_async_cleanup(asdl);
> +
> + if (notifier->unbind)
> + notifier->unbind(notifier, asdl);
> +
> + mutex_unlock(&list_lock);
> +}
> +EXPORT_SYMBOL(v4l2_async_unregister_subdev);
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> new file mode 100644
> index 0000000..c638f5c
> --- /dev/null
> +++ b/include/media/v4l2-async.h
> @@ -0,0 +1,99 @@
> +/*
> + * V4L2 asynchronous subdevice registration API
> + *
> + * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef V4L2_ASYNC_H
> +#define V4L2_ASYNC_H
> +
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +
> +struct device;
> +struct v4l2_device;
> +struct v4l2_subdev;
> +struct v4l2_async_notifier;
> +
> +enum v4l2_async_bus_type {
> + V4L2_ASYNC_BUS_CUSTOM,
> + V4L2_ASYNC_BUS_PLATFORM,
> + V4L2_ASYNC_BUS_I2C,
> +};
> +
> +struct v4l2_async_hw_info {
> + enum v4l2_async_bus_type bus_type;
> + union {
> + struct {
> + const char *name;
> + } platform;
> + struct {
> + int adapter_id;
> + unsigned short address;
> + } i2c;
> + struct {
> + bool (*match)(struct device *,
> + struct v4l2_async_hw_info *);
> + void *priv;
> + } custom;
> + } match;
> +};
> +
> +/**
> + * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> + * @hw: this device descriptor
> + * @list: member in a list of subdevices
> + */
> +struct v4l2_async_subdev {
> + struct v4l2_async_hw_info hw;
> + struct list_head list;
> +};
> +
> +/**
> + * v4l2_async_subdev_list - provided by subdevices
> + * @list: member in a list of subdevices
> + * @asd: pointer to respective struct v4l2_async_subdev
> + * @notifier: pointer to managing notifier
> + */
> +struct v4l2_async_subdev_list {
> + struct list_head list;
> + struct v4l2_async_subdev *asd;
> + struct v4l2_async_notifier *notifier;
> +};
> +
> +/**
> + * v4l2_async_notifier - provided by bridges
It probably makes sense to just say e.g.
v4l2_async_notifier - v4l2_device notifier data structure
I mean at least "bridge" to me doesn't sound generic enough.
> + * @subdev_num: number of subdevices
> + * @subdev: array of pointers to subdevices
> + * @v4l2_dev: pointer to struct v4l2_device
> + * @waiting: list of subdevices, waiting for their drivers
> + * @done: list of subdevices, already probed
> + * @list: member in a global list of notifiers
> + * @bound: a subdevice driver has successfully probed one of subdevices
> + * @complete: all subdevices have been probed successfully
> + * @unbind: a subdevice is leaving
> + */
> +struct v4l2_async_notifier {
> + unsigned int subdev_num;
> + struct v4l2_async_subdev **subdev;
> + struct v4l2_device *v4l2_dev;
> + struct list_head waiting;
> + struct list_head done;
> + struct list_head list;
> + int (*bound)(struct v4l2_async_notifier *notifier,
> + struct v4l2_async_subdev_list *asdl);
> + int (*complete)(struct v4l2_async_notifier *notifier);
> + void (*unbind)(struct v4l2_async_notifier *notifier,
> + struct v4l2_async_subdev_list *asdl);
I would preffer to simply pass struct v4l2_subdev * to bound/unbind.
Since it is about just one subdevice's status change, why do we need
struct v4l2_async_subdev_list ?
> +};
> +
> +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> + struct v4l2_async_notifier *notifier);
> +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
How about naming it v4l2_device_notifier_(un)register() ?
> +int v4l2_async_register_subdev(struct v4l2_subdev *sd);
> +void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
Hopefully, one day it just becomes v4l2_(un)register_subdev() :-)
> +#endif
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 5298d67..21174af 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -24,6 +24,7 @@
> #include <linux/types.h>
> #include <linux/v4l2-subdev.h>
> #include <media/media-entity.h>
> +#include <media/v4l2-async.h>
> #include <media/v4l2-common.h>
> #include <media/v4l2-dev.h>
> #include <media/v4l2-fh.h>
> @@ -585,8 +586,17 @@ struct v4l2_subdev {
> void *host_priv;
> /* subdev device node */
> struct video_device *devnode;
> + /* pointer to the physical device */
> + struct device *dev;
> + struct v4l2_async_subdev_list asdl;
Why not embed respective fields directly in struct v4l2_subdev, rather
than adding this new data structure ? I find this all code pretty much
convoluted, probably one of the reason is that there are multiple
list_head objects at various levels.
> };
>
> +static inline struct v4l2_subdev *v4l2_async_to_subdev(
> + struct v4l2_async_subdev_list *asdl)
> +{
> + return container_of(asdl, struct v4l2_subdev, asdl);
> +}
> +
> #define media_entity_to_v4l2_subdev(ent) \
> container_of(ent, struct v4l2_subdev, entity)
> #define vdev_to_v4l2_subdev(vdev) \
>
Thanks,
Sylwester
WARNING: multiple messages have this Message-ID (diff)
From: Sylwester Nawrocki <s.nawrocki@samsung.com>
To: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: linux-media@vger.kernel.org,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Hans Verkuil <hverkuil@xs4all.nl>,
linux-sh@vger.kernel.org, Magnus Damm <magnus.damm@gmail.com>,
Sakari Ailus <sakari.ailus@iki.fi>,
Prabhakar Lad <prabhakar.lad@ti.com>
Subject: Re: [PATCH v9 02/20] V4L2: support asynchronous subdevice registration
Date: Mon, 15 Apr 2013 13:57:17 +0200 [thread overview]
Message-ID: <516BEB1D.80105@samsung.com> (raw)
In-Reply-To: <1365781240-16149-3-git-send-email-g.liakhovetski@gmx.de>
Hi Guennadi,
On 04/12/2013 05:40 PM, Guennadi Liakhovetski wrote:
> Currently bridge device drivers register devices for all subdevices
> synchronously, tupically, during their probing. E.g. if an I2C CMOS sensor
> is attached to a video bridge device, the bridge driver will create an I2C
> device and wait for the respective I2C driver to probe. This makes linking
> of devices straight forward, but this approach cannot be used with
> intrinsically asynchronous and unordered device registration systems like
> the Flattened Device Tree. To support such systems this patch adds an
> asynchronous subdevice registration framework to V4L2. To use it respective
> (e.g. I2C) subdevice drivers must register themselves with the framework.
> A bridge driver on the other hand must register notification callbacks,
> that will be called upon various related events.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
>
> v9: addressed Laurent's comments (thanks)
> 1. moved valid hw->bus_type check
> 2. made v4l2_async_unregister() void
> 3. renamed struct v4l2_async_hw_device to struct v4l2_async_hw_info
> 4. merged struct v4l2_async_subdev_list into struct v4l2_subdev
> 5. fixed a typo
> 6. made subdev_num unsigned
>
> drivers/media/v4l2-core/Makefile | 3 +-
> drivers/media/v4l2-core/v4l2-async.c | 284 ++++++++++++++++++++++++++++++++++
> include/media/v4l2-async.h | 99 ++++++++++++
> include/media/v4l2-subdev.h | 10 ++
> 4 files changed, 395 insertions(+), 1 deletions(-)
> create mode 100644 drivers/media/v4l2-core/v4l2-async.c
> create mode 100644 include/media/v4l2-async.h
>
> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
> index 628c630..4c33b8d6 100644
> --- a/drivers/media/v4l2-core/Makefile
> +++ b/drivers/media/v4l2-core/Makefile
> @@ -5,7 +5,8 @@
> tuner-objs := tuner-core.o
>
> videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
> - v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o
> + v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o \
> + v4l2-async.o
> ifeq ($(CONFIG_COMPAT),y)
> videodev-objs += v4l2-compat-ioctl32.o
> endif
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> new file mode 100644
> index 0000000..98db2e0
> --- /dev/null
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -0,0 +1,284 @@
> +/*
> + * V4L2 asynchronous subdevice registration API
> + *
> + * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
[...]
> +static void v4l2_async_cleanup(struct v4l2_async_subdev_list *asdl)
> +{
> + struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
> +
> + v4l2_device_unregister_subdev(sd);
> + /* Subdevice driver will reprobe and put asdl back onto the list */
> + list_del_init(&asdl->list);
> + asdl->asd = NULL;
> + sd->dev = NULL;
> +}
> +
> +static void v4l2_async_unregister(struct v4l2_async_subdev_list *asdl)
> +{
> + struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
> +
> + v4l2_async_cleanup(asdl);
> +
> + /* If we handled USB devices, we'd have to lock the parent too */
> + device_release_driver(sd->dev);
> +}
> +
> +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> + struct v4l2_async_notifier *notifier)
> +{
> + struct v4l2_async_subdev_list *asdl, *tmp;
> + struct v4l2_async_subdev *asd;
> + int i;
> +
> + notifier->v4l2_dev = v4l2_dev;
> + INIT_LIST_HEAD(¬ifier->waiting);
> + INIT_LIST_HEAD(¬ifier->done);
> +
> + for (i = 0; i < notifier->subdev_num; i++) {
> + asd = notifier->subdev[i];
> +
> + switch (asd->hw.bus_type) {
> + case V4L2_ASYNC_BUS_CUSTOM:
> + case V4L2_ASYNC_BUS_PLATFORM:
> + case V4L2_ASYNC_BUS_I2C:
> + break;
> + default:
> + dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
> + "Invalid bus-type %u on %p\n",
> + asd->hw.bus_type, asd);
> + return -EINVAL;
> + }
> + list_add_tail(&asd->list, ¬ifier->waiting);
> + }
> +
> + mutex_lock(&list_lock);
> +
> + /* Keep also completed notifiers on the list */
> + list_add(¬ifier->list, ¬ifier_list);
> +
> + list_for_each_entry_safe(asdl, tmp, &subdev_list, list) {
> + int ret;
> +
> + asd = v4l2_async_belongs(notifier, asdl);
> + if (!asd)
> + continue;
> +
> + ret = v4l2_async_test_notify(notifier, asdl, asd);
> + if (ret < 0) {
> + mutex_unlock(&list_lock);
> + return ret;
> + }
> + }
> +
> + mutex_unlock(&list_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(v4l2_async_notifier_register);
> +
> +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> +{
> + struct v4l2_async_subdev_list *asdl, *tmp;
> + int i = 0;
> + struct device **dev = kcalloc(notifier->subdev_num,
> + sizeof(*dev), GFP_KERNEL);
> + if (!dev)
> + dev_err(notifier->v4l2_dev->dev,
> + "Failed to allocate device cache!\n");
> +
> + mutex_lock(&list_lock);
> +
> + list_del(¬ifier->list);
> +
> + list_for_each_entry_safe(asdl, tmp, ¬ifier->done, list) {
> + if (dev) {
> + struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
> + dev[i++] = get_device(sd->dev);
> + }
> + v4l2_async_unregister(asdl);
Hmm, couldn't we do without the **dev array ? Now when struct v42_subdev has
struct device * embedded in it ?
And if we can't get hold off struct device object is it safe to call
v4l2_async_unregister(), which references it ?
Why is get_device() optional ? Some comment might be useful here.
> +
> + if (notifier->unbind)
> + notifier->unbind(notifier, asdl);
> + }
> +
> + mutex_unlock(&list_lock);
> +
> + if (dev) {
> + while (i--) {
> + if (dev[i] && device_attach(dev[i]) < 0)
> + dev_err(dev[i], "Failed to re-probe to %s\n",
> + dev[i]->driver ? dev[i]->driver->name : "(none)");
Is it safe to reference dev->driver without holding struct device::mutex ?
> + put_device(dev[i]);
> + }
> + kfree(dev);
> + }
> + /*
> + * Don't care about the waiting list, it is initialised and populated
> + * upon notifier registration.
> + */
> +}
> +EXPORT_SYMBOL(v4l2_async_notifier_unregister);
> +
> +int v4l2_async_register_subdev(struct v4l2_subdev *sd)
> +{
> + struct v4l2_async_subdev_list *asdl = &sd->asdl;
> + struct v4l2_async_notifier *notifier;
> +
> + mutex_lock(&list_lock);
> +
> + INIT_LIST_HEAD(&asdl->list);
> +
> + list_for_each_entry(notifier, ¬ifier_list, list) {
> + struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, asdl);
> + if (asd) {
> + int ret = v4l2_async_test_notify(notifier, asdl, asd);
> + mutex_unlock(&list_lock);
> + return ret;
> + }
> + }
> +
> + /* None matched, wait for hot-plugging */
> + list_add(&asdl->list, &subdev_list);
> +
> + mutex_unlock(&list_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(v4l2_async_register_subdev);
> +
> +void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
> +{
> + struct v4l2_async_subdev_list *asdl = &sd->asdl;
> + struct v4l2_async_notifier *notifier = asdl->notifier;
> + struct device *dev;
This variable appears unused, except a single assignment below.
> + if (!asdl->asd) {
> + if (!list_empty(&asdl->list))
> + v4l2_async_cleanup(asdl);
> + return;
> + }
> +
> + mutex_lock(&list_lock);
> +
> + dev = sd->dev;
> + list_add(&asdl->asd->list, ¬ifier->waiting);
> +
> + v4l2_async_cleanup(asdl);
> +
> + if (notifier->unbind)
> + notifier->unbind(notifier, asdl);
> +
> + mutex_unlock(&list_lock);
> +}
> +EXPORT_SYMBOL(v4l2_async_unregister_subdev);
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> new file mode 100644
> index 0000000..c638f5c
> --- /dev/null
> +++ b/include/media/v4l2-async.h
> @@ -0,0 +1,99 @@
> +/*
> + * V4L2 asynchronous subdevice registration API
> + *
> + * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef V4L2_ASYNC_H
> +#define V4L2_ASYNC_H
> +
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +
> +struct device;
> +struct v4l2_device;
> +struct v4l2_subdev;
> +struct v4l2_async_notifier;
> +
> +enum v4l2_async_bus_type {
> + V4L2_ASYNC_BUS_CUSTOM,
> + V4L2_ASYNC_BUS_PLATFORM,
> + V4L2_ASYNC_BUS_I2C,
> +};
> +
> +struct v4l2_async_hw_info {
> + enum v4l2_async_bus_type bus_type;
> + union {
> + struct {
> + const char *name;
> + } platform;
> + struct {
> + int adapter_id;
> + unsigned short address;
> + } i2c;
> + struct {
> + bool (*match)(struct device *,
> + struct v4l2_async_hw_info *);
> + void *priv;
> + } custom;
> + } match;
> +};
> +
> +/**
> + * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> + * @hw: this device descriptor
> + * @list: member in a list of subdevices
> + */
> +struct v4l2_async_subdev {
> + struct v4l2_async_hw_info hw;
> + struct list_head list;
> +};
> +
> +/**
> + * v4l2_async_subdev_list - provided by subdevices
> + * @list: member in a list of subdevices
> + * @asd: pointer to respective struct v4l2_async_subdev
> + * @notifier: pointer to managing notifier
> + */
> +struct v4l2_async_subdev_list {
> + struct list_head list;
> + struct v4l2_async_subdev *asd;
> + struct v4l2_async_notifier *notifier;
> +};
> +
> +/**
> + * v4l2_async_notifier - provided by bridges
It probably makes sense to just say e.g.
v4l2_async_notifier - v4l2_device notifier data structure
I mean at least "bridge" to me doesn't sound generic enough.
> + * @subdev_num: number of subdevices
> + * @subdev: array of pointers to subdevices
> + * @v4l2_dev: pointer to struct v4l2_device
> + * @waiting: list of subdevices, waiting for their drivers
> + * @done: list of subdevices, already probed
> + * @list: member in a global list of notifiers
> + * @bound: a subdevice driver has successfully probed one of subdevices
> + * @complete: all subdevices have been probed successfully
> + * @unbind: a subdevice is leaving
> + */
> +struct v4l2_async_notifier {
> + unsigned int subdev_num;
> + struct v4l2_async_subdev **subdev;
> + struct v4l2_device *v4l2_dev;
> + struct list_head waiting;
> + struct list_head done;
> + struct list_head list;
> + int (*bound)(struct v4l2_async_notifier *notifier,
> + struct v4l2_async_subdev_list *asdl);
> + int (*complete)(struct v4l2_async_notifier *notifier);
> + void (*unbind)(struct v4l2_async_notifier *notifier,
> + struct v4l2_async_subdev_list *asdl);
I would preffer to simply pass struct v4l2_subdev * to bound/unbind.
Since it is about just one subdevice's status change, why do we need
struct v4l2_async_subdev_list ?
> +};
> +
> +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> + struct v4l2_async_notifier *notifier);
> +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
How about naming it v4l2_device_notifier_(un)register() ?
> +int v4l2_async_register_subdev(struct v4l2_subdev *sd);
> +void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
Hopefully, one day it just becomes v4l2_(un)register_subdev() :-)
> +#endif
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 5298d67..21174af 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -24,6 +24,7 @@
> #include <linux/types.h>
> #include <linux/v4l2-subdev.h>
> #include <media/media-entity.h>
> +#include <media/v4l2-async.h>
> #include <media/v4l2-common.h>
> #include <media/v4l2-dev.h>
> #include <media/v4l2-fh.h>
> @@ -585,8 +586,17 @@ struct v4l2_subdev {
> void *host_priv;
> /* subdev device node */
> struct video_device *devnode;
> + /* pointer to the physical device */
> + struct device *dev;
> + struct v4l2_async_subdev_list asdl;
Why not embed respective fields directly in struct v4l2_subdev, rather
than adding this new data structure ? I find this all code pretty much
convoluted, probably one of the reason is that there are multiple
list_head objects at various levels.
> };
>
> +static inline struct v4l2_subdev *v4l2_async_to_subdev(
> + struct v4l2_async_subdev_list *asdl)
> +{
> + return container_of(asdl, struct v4l2_subdev, asdl);
> +}
> +
> #define media_entity_to_v4l2_subdev(ent) \
> container_of(ent, struct v4l2_subdev, entity)
> #define vdev_to_v4l2_subdev(vdev) \
>
Thanks,
Sylwester
next prev parent reply other threads:[~2013-04-15 11:57 UTC|newest]
Thread overview: 66+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-12 15:40 [PATCH v9 00/20] V4L2 clock and async patches and soc-camera example Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 01/20] V4L2: add temporary clock helpers Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 02/20] V4L2: support asynchronous subdevice registration Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-15 11:57 ` Sylwester Nawrocki [this message]
2013-04-15 11:57 ` Sylwester Nawrocki
2013-04-22 11:39 ` Laurent Pinchart
2013-04-22 11:39 ` Laurent Pinchart
2013-04-23 13:01 ` Guennadi Liakhovetski
2013-04-23 13:01 ` Guennadi Liakhovetski
2013-04-26 20:46 ` Sylwester Nawrocki
2013-04-26 20:46 ` Sylwester Nawrocki
2013-04-15 14:22 ` Prabhakar Lad
2013-04-15 14:34 ` Prabhakar Lad
2013-04-22 7:17 ` Prabhakar Lad
2013-04-22 7:29 ` Prabhakar Lad
2013-04-26 8:44 ` Sascha Hauer
2013-04-26 8:44 ` Sascha Hauer
2013-04-26 21:07 ` Guennadi Liakhovetski
2013-04-26 21:07 ` Guennadi Liakhovetski
2013-04-29 10:01 ` Sascha Hauer
2013-04-29 10:01 ` Sascha Hauer
2013-04-30 13:53 ` Sascha Hauer
2013-04-30 13:53 ` Sascha Hauer
2013-04-30 14:06 ` Guennadi Liakhovetski
2013-04-30 14:06 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 03/20] soc-camera: move common code to soc_camera.c Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 04/20] soc-camera: add host clock callbacks to start and stop the master clock Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 05/20] pxa-camera: move interface activation and deactivation to clock callbacks Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 06/20] omap1-camera: " Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 07/20] atmel-isi: " Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 08/20] mx3-camera: " Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 09/20] mx2-camera: " Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 10/20] mx1-camera: " Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 11/20] sh-mobile-ceu-camera: " Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 12/20] soc-camera: make .clock_{start,stop} compulsory, .add / .remove optional Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 13/20] soc-camera: don't attach the client to the host during probing Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 14/20] sh-mobile-ceu-camera: add primitive OF support Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 15/20] sh-mobile-ceu-driver: support max width and height in DT Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-13 21:22 ` Sergei Shtylyov
2013-04-13 21:22 ` Sergei Shtylyov
2013-04-12 15:40 ` [PATCH v9 16/20] soc-camera: switch I2C subdevice drivers to use v4l2-clk Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 17/20] soc-camera: add V4L2-async support Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 18/20] sh_mobile_ceu_camera: add asynchronous subdevice probing support Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 19/20] imx074: support asynchronous probing Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
2013-04-12 15:40 ` [PATCH v9 20/20] ARM: shmobile: convert ap4evb to asynchronously register camera subdevices Guennadi Liakhovetski
2013-04-12 15:40 ` Guennadi Liakhovetski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=516BEB1D.80105@samsung.com \
--to=s.nawrocki@samsung.com \
--cc=g.liakhovetski@gmx.de \
--cc=hverkuil@xs4all.nl \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=linux-sh@vger.kernel.org \
--cc=magnus.damm@gmail.com \
--cc=prabhakar.lad@ti.com \
--cc=sakari.ailus@iki.fi \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.