int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
{
- if (dev == NULL || v4l2_dev == NULL)
+ if (v4l2_dev == NULL)
return -EINVAL;
- /* Warn if we apparently re-register a device */
- WARN_ON(dev_get_drvdata(dev) != NULL);
+
INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock);
v4l2_dev->dev = dev;
- snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
+ if (dev == NULL) {
+ /* If dev == NULL, then name must be filled in by the caller */
+ WARN_ON(!v4l2_dev->name[0]);
+ return 0;
+ }
+
+ /* Set name to driver name + device name if it is empty. */
+ if (!v4l2_dev->name[0])
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
dev->driver->name, dev_name(dev));
+ if (dev_get_drvdata(dev))
+ v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");
dev_set_drvdata(dev, v4l2_dev);
return 0;
}
{
struct v4l2_subdev *sd, *next;
- if (v4l2_dev == NULL || v4l2_dev->dev == NULL)
+ if (v4l2_dev == NULL)
return;
- dev_set_drvdata(v4l2_dev->dev, NULL);
- /* unregister subdevs */
+ if (v4l2_dev->dev)
+ dev_set_drvdata(v4l2_dev->dev, NULL);
+ /* Unregister subdevs */
list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
v4l2_device_unregister_subdev(sd);
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister);
-int v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd)
+int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+ struct v4l2_subdev *sd)
{
/* Check for valid input */
- if (dev == NULL || sd == NULL || !sd->name[0])
+ if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
return -EINVAL;
/* Warn if we apparently re-register a subdev */
WARN_ON(sd->dev != NULL);
if (!try_module_get(sd->owner))
return -ENODEV;
- sd->dev = dev;
- spin_lock(&dev->lock);
- list_add_tail(&sd->list, &dev->subdevs);
- spin_unlock(&dev->lock);
+ sd->dev = v4l2_dev;
+ spin_lock(&v4l2_dev->lock);
+ list_add_tail(&sd->list, &v4l2_dev->subdevs);
+ spin_unlock(&v4l2_dev->lock);
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
#define V4L2_DEVICE_NAME_SIZE (BUS_ID_SIZE + 16)
struct v4l2_device {
- /* dev->driver_data points to this struct */
+ /* dev->driver_data points to this struct.
+ Note: dev might be NULL if there is no parent device
+ as is the case with e.g. ISA devices. */
struct device *dev;
/* used to keep track of the registered subdevs */
struct list_head subdevs;
char name[V4L2_DEVICE_NAME_SIZE];
};
-/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev */
+/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev.
+ dev may be NULL in rare cases (ISA devices). In that case you
+ must fill in the v4l2_dev->name field before calling this function. */
int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
/* Set v4l2_dev->dev->driver_data to NULL and unregister all sub-devices */
void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
/* Register a subdev with a v4l2 device. While registered the subdev module
is marked as in-use. An error is returned if the module is no longer
loaded when you attempt to register it. */
-int __must_check v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd);
+int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+ struct v4l2_subdev *sd);
/* Unregister a subdev with a v4l2 device. Can also be called if the subdev
wasn't registered. In that case it will do nothing. */
void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
/* Iterate over all subdevs. */
-#define v4l2_device_for_each_subdev(sd, dev) \
- list_for_each_entry(sd, &(dev)->subdevs, list)
+#define v4l2_device_for_each_subdev(sd, v4l2_dev) \
+ list_for_each_entry(sd, &(v4l2_dev)->subdevs, list)
/* Call the specified callback for all subdevs matching the condition.
Ignore any errors. Note that you cannot add or delete a subdev
while walking the subdevs list. */
-#define __v4l2_device_call_subdevs(dev, cond, o, f, args...) \
+#define __v4l2_device_call_subdevs(v4l2_dev, cond, o, f, args...) \
do { \
struct v4l2_subdev *sd; \
\
- list_for_each_entry(sd, &(dev)->subdevs, list) \
+ list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) \
if ((cond) && sd->ops->o && sd->ops->o->f) \
sd->ops->o->f(sd , ##args); \
} while (0)
If the callback returns an error other than 0 or -ENOIOCTLCMD, then
return with that error code. Note that you cannot add or delete a
subdev while walking the subdevs list. */
-#define __v4l2_device_call_subdevs_until_err(dev, cond, o, f, args...) \
+#define __v4l2_device_call_subdevs_until_err(v4l2_dev, cond, o, f, args...) \
({ \
struct v4l2_subdev *sd; \
long err = 0; \
\
- list_for_each_entry(sd, &(dev)->subdevs, list) { \
+ list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) { \
if ((cond) && sd->ops->o && sd->ops->o->f) \
err = sd->ops->o->f(sd , ##args); \
if (err && err != -ENOIOCTLCMD) \
/* Call the specified callback for all subdevs matching grp_id (if 0, then
match them all). Ignore any errors. Note that you cannot add or delete
a subdev while walking the subdevs list. */
-#define v4l2_device_call_all(dev, grpid, o, f, args...) \
- __v4l2_device_call_subdevs(dev, \
+#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...) \
+ __v4l2_device_call_subdevs(v4l2_dev, \
!(grpid) || sd->grp_id == (grpid), o, f , ##args)
/* Call the specified callback for all subdevs matching grp_id (if 0, then
match them all). If the callback returns an error other than 0 or
-ENOIOCTLCMD, then return with that error code. Note that you cannot
add or delete a subdev while walking the subdevs list. */
-#define v4l2_device_call_until_err(dev, grpid, o, f, args...) \
- __v4l2_device_call_subdevs_until_err(dev, \
+#define v4l2_device_call_until_err(v4l2_dev, grpid, o, f, args...) \
+ __v4l2_device_call_subdevs_until_err(v4l2_dev, \
!(grpid) || sd->grp_id == (grpid), o, f , ##args)
#endif