|
@@ -320,33 +320,6 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
|
|
|
|
|
|
-static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
|
|
|
- unsigned int max_subdevs)
|
|
|
-{
|
|
|
- struct v4l2_async_subdev **subdevs;
|
|
|
-
|
|
|
- if (max_subdevs <= notifier->max_subdevs)
|
|
|
- return 0;
|
|
|
-
|
|
|
- subdevs = kvmalloc_array(
|
|
|
- max_subdevs, sizeof(*notifier->subdevs),
|
|
|
- GFP_KERNEL | __GFP_ZERO);
|
|
|
- if (!subdevs)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- if (notifier->subdevs) {
|
|
|
- memcpy(subdevs, notifier->subdevs,
|
|
|
- sizeof(*subdevs) * notifier->num_subdevs);
|
|
|
-
|
|
|
- kvfree(notifier->subdevs);
|
|
|
- }
|
|
|
-
|
|
|
- notifier->subdevs = subdevs;
|
|
|
- notifier->max_subdevs = max_subdevs;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int v4l2_async_notifier_fwnode_parse_endpoint(
|
|
|
struct device *dev, struct v4l2_async_notifier *notifier,
|
|
|
struct fwnode_handle *endpoint, unsigned int asd_struct_size,
|
|
@@ -391,8 +364,13 @@ static int v4l2_async_notifier_fwnode_parse_endpoint(
|
|
|
if (ret < 0)
|
|
|
goto out_err;
|
|
|
|
|
|
- notifier->subdevs[notifier->num_subdevs] = asd;
|
|
|
- notifier->num_subdevs++;
|
|
|
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
|
|
|
+ if (ret < 0) {
|
|
|
+ /* not an error if asd already exists */
|
|
|
+ if (ret == -EEXIST)
|
|
|
+ ret = 0;
|
|
|
+ goto out_err;
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -411,46 +389,11 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints(
|
|
|
struct v4l2_async_subdev *asd))
|
|
|
{
|
|
|
struct fwnode_handle *fwnode;
|
|
|
- unsigned int max_subdevs = notifier->max_subdevs;
|
|
|
- int ret;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
|
|
|
- dev_fwnode(dev), fwnode)); ) {
|
|
|
- struct fwnode_handle *dev_fwnode;
|
|
|
- bool is_available;
|
|
|
-
|
|
|
- dev_fwnode = fwnode_graph_get_port_parent(fwnode);
|
|
|
- is_available = fwnode_device_is_available(dev_fwnode);
|
|
|
- fwnode_handle_put(dev_fwnode);
|
|
|
- if (!is_available)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (has_port) {
|
|
|
- struct fwnode_endpoint ep;
|
|
|
-
|
|
|
- ret = fwnode_graph_parse_endpoint(fwnode, &ep);
|
|
|
- if (ret) {
|
|
|
- fwnode_handle_put(fwnode);
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- if (ep.port != port)
|
|
|
- continue;
|
|
|
- }
|
|
|
- max_subdevs++;
|
|
|
- }
|
|
|
-
|
|
|
- /* No subdevs to add? Return here. */
|
|
|
- if (max_subdevs == notifier->max_subdevs)
|
|
|
- return 0;
|
|
|
-
|
|
|
- ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
|
|
|
dev_fwnode(dev), fwnode)); ) {
|
|
|
struct fwnode_handle *dev_fwnode;
|
|
@@ -473,11 +416,6 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints(
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
|
|
|
- ret = -EINVAL;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
ret = v4l2_async_notifier_fwnode_parse_endpoint(
|
|
|
dev, notifier, fwnode, asd_struct_size, parse_endpoint);
|
|
|
if (ret < 0)
|
|
@@ -548,31 +486,23 @@ static int v4l2_fwnode_reference_parse(
|
|
|
if (ret != -ENOENT && ret != -ENODATA)
|
|
|
return ret;
|
|
|
|
|
|
- ret = v4l2_async_notifier_realloc(notifier,
|
|
|
- notifier->num_subdevs + index);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
for (index = 0; !fwnode_property_get_reference_args(
|
|
|
dev_fwnode(dev), prop, NULL, 0, index, &args);
|
|
|
index++) {
|
|
|
struct v4l2_async_subdev *asd;
|
|
|
|
|
|
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
|
|
|
- ret = -EINVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
+ asd = v4l2_async_notifier_add_fwnode_subdev(
|
|
|
+ notifier, args.fwnode, sizeof(*asd));
|
|
|
+ if (IS_ERR(asd)) {
|
|
|
+ ret = PTR_ERR(asd);
|
|
|
+ /* not an error if asd already exists */
|
|
|
+ if (ret == -EEXIST) {
|
|
|
+ fwnode_handle_put(args.fwnode);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- asd = kzalloc(sizeof(*asd), GFP_KERNEL);
|
|
|
- if (!asd) {
|
|
|
- ret = -ENOMEM;
|
|
|
goto error;
|
|
|
}
|
|
|
-
|
|
|
- notifier->subdevs[notifier->num_subdevs] = asd;
|
|
|
- asd->match.fwnode = args.fwnode;
|
|
|
- asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
|
|
|
- notifier->num_subdevs++;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -843,31 +773,23 @@ static int v4l2_fwnode_reference_parse_int_props(
|
|
|
index++;
|
|
|
} while (1);
|
|
|
|
|
|
- ret = v4l2_async_notifier_realloc(notifier,
|
|
|
- notifier->num_subdevs + index);
|
|
|
- if (ret)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
|
|
|
dev_fwnode(dev), prop, index, props,
|
|
|
nprops))); index++) {
|
|
|
struct v4l2_async_subdev *asd;
|
|
|
|
|
|
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
|
|
|
- ret = -EINVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
+ asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
|
|
|
+ sizeof(*asd));
|
|
|
+ if (IS_ERR(asd)) {
|
|
|
+ ret = PTR_ERR(asd);
|
|
|
+ /* not an error if asd already exists */
|
|
|
+ if (ret == -EEXIST) {
|
|
|
+ fwnode_handle_put(fwnode);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
|
|
|
- if (!asd) {
|
|
|
- ret = -ENOMEM;
|
|
|
goto error;
|
|
|
}
|
|
|
-
|
|
|
- notifier->subdevs[notifier->num_subdevs] = asd;
|
|
|
- asd->match.fwnode = fwnode;
|
|
|
- asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
|
|
|
- notifier->num_subdevs++;
|
|
|
}
|
|
|
|
|
|
return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
|
|
@@ -924,6 +846,8 @@ int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
|
|
|
if (!notifier)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
+ v4l2_async_notifier_init(notifier);
|
|
|
+
|
|
|
ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
|
|
|
notifier);
|
|
|
if (ret < 0)
|