All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pratyush Yadav <p.yadav@ti.com>
To: u-boot@lists.denx.de
Subject: [RFC PATCH 1/1] gpio: Handle NULL pointers gracefully
Date: Sat, 30 May 2020 03:33:55 +0530	[thread overview]
Message-ID: <20200529220355.4396-2-p.yadav@ti.com> (raw)
In-Reply-To: <20200529220355.4396-1-p.yadav@ti.com>

Prepare the way for a managed GPIO API by handling NULL pointers without
crashing or failing. validate_desc() comes from Linux with the prints
removed to reduce code size.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/gpio/Kconfig       |  9 ++++
 drivers/gpio/gpio-uclass.c | 86 ++++++++++++++++++++++++++++++++++----
 include/asm-generic/gpio.h |  2 +-
 3 files changed, 88 insertions(+), 9 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d87f6cc105..f8b6bcdf44 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -36,6 +36,15 @@ config TPL_DM_GPIO
 	  particular GPIOs that they provide. The uclass interface
 	  is defined in include/asm-generic/gpio.h.

+config GPIO_VALIDATE_DESC
+	bool "Check if GPIO descriptor is NULL and bail out if it is"
+	depends on DM_GPIO
+	default y
+	help
+	  If a GPIO is optional, the GPIO descriptor is NULL. In that
+	  case, calls should bail out instead of causing NULL pointer
+	  access.
+
 config GPIO_HOG
 	bool "Enable GPIO hog support"
 	depends on DM_GPIO
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 9eeab22eef..6b97d3aaff 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -20,6 +20,25 @@

 DECLARE_GLOBAL_DATA_PTR;

+#ifdef CONFIG_GPIO_VALIDATE_DESC
+/*
+ * This descriptor validation needs to be inserted verbatim into each
+ * function taking a descriptor, so we need to use a preprocessor
+ * macro to avoid endless duplication. If the desc is NULL it is an
+ * optional GPIO and calls should just bail out.
+ */
+static inline int validate_desc(const struct gpio_desc *desc)
+{
+	if (!desc)
+		return 0;
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+	if (!desc->dev)
+		return -EINVAL;
+	return 1;
+}
+#endif
+
 /**
  * gpio_desc_init() - Initialize the GPIO descriptor
  *
@@ -303,11 +322,19 @@ int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc)

 int dm_gpio_request(struct gpio_desc *desc, const char *label)
 {
-	struct udevice *dev = desc->dev;
+	struct udevice *dev;
 	struct gpio_dev_priv *uc_priv;
 	char *str;
 	int ret;

+#ifdef CONFIG_GPIO_VALIDATE_DESC
+	ret = validate_desc(desc);
+	if (ret <= 0)
+		return ret;
+#endif
+
+	dev = desc->dev;
+
 	uc_priv = dev_get_uclass_priv(dev);
 	if (uc_priv->name[desc->offset])
 		return -EBUSY;
@@ -434,6 +461,14 @@ static int check_reserved(const struct gpio_desc *desc, const char *func)
 {
 	struct gpio_dev_priv *uc_priv;

+#ifdef CONFIG_GPIO_VALIDATE_DESC
+	int ret;
+
+	ret = validate_desc(desc);
+	if (ret <= 0)
+		return ret;
+#endif
+
 	if (!dm_gpio_is_valid(desc))
 		return -ENOENT;

@@ -510,6 +545,12 @@ int dm_gpio_get_value(const struct gpio_desc *desc)
 {
 	int ret;

+#ifdef CONFIG_GPIO_VALIDATE_DESC
+	ret = validate_desc(desc);
+	if (ret <= 0)
+		return ret;
+#endif
+
 	ret = check_reserved(desc, "get_value");
 	if (ret)
 		return ret;
@@ -521,6 +562,12 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value)
 {
 	int ret;

+#ifdef CONFIG_GPIO_VALIDATE_DESC
+	ret = validate_desc(desc);
+	if (ret <= 0)
+		return ret;
+#endif
+
 	ret = check_reserved(desc, "set_value");
 	if (ret)
 		return ret;
@@ -572,11 +619,21 @@ static int check_dir_flags(ulong flags)

 static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
 {
-	struct udevice *dev = desc->dev;
-	struct dm_gpio_ops *ops = gpio_get_ops(dev);
-	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct udevice *dev;
+	struct dm_gpio_ops *ops;
+	struct gpio_dev_priv *uc_priv;
 	int ret = 0;

+#ifdef CONFIG_GPIO_VALIDATE_DESC
+	ret = validate_desc(desc);
+	if (ret <= 0)
+		return ret;
+#endif
+
+	dev = desc->dev;
+	ops = gpio_get_ops(dev);
+	uc_priv = dev_get_uclass_priv(dev);
+
 	ret = check_dir_flags(flags);
 	if (ret) {
 		dev_dbg(dev,
@@ -1043,6 +1100,14 @@ int gpio_get_list_count(struct udevice *dev, const char *list_name)

 int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
 {
+#ifdef CONFIG_GPIO_VALIDATE_DESC
+	int ret;
+
+	ret = validate_desc(desc);
+	if (ret <= 0)
+		return ret;
+#endif
+
 	/* For now, we don't do any checking of dev */
 	return _dm_gpio_free(desc->dev, desc->offset);
 }
@@ -1091,12 +1156,17 @@ static int gpio_renumber(struct udevice *removed_dev)

 int gpio_get_number(const struct gpio_desc *desc)
 {
-	struct udevice *dev = desc->dev;
 	struct gpio_dev_priv *uc_priv;

-	if (!dev)
-		return -1;
-	uc_priv = dev->uclass_priv;
+#ifdef CONFIG_GPIO_VALIDATE_DESC
+	int ret;
+
+	ret = validate_desc(desc);
+	if (ret <= 0)
+		return ret;
+#endif
+
+	uc_priv = dev_get_uclass_priv(desc->dev);

 	return uc_priv->gpio_base + desc->offset;
 }
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index e16c2f31d9..46007b1283 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -149,7 +149,7 @@ struct gpio_desc {
  */
 static inline bool dm_gpio_is_valid(const struct gpio_desc *desc)
 {
-	return desc->dev != NULL;
+	return desc && desc->dev;
 }

 /**
--
2.26.2

  reply	other threads:[~2020-05-29 22:03 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-29 22:03 [RFC PATCH 0/1] gpio: Handle NULL pointers gracefully Pratyush Yadav
2020-05-29 22:03 ` Pratyush Yadav [this message]
2020-06-01 17:08   ` [RFC PATCH 1/1] " Simon Glass
2020-06-08 12:37     ` Pratyush Yadav
2020-06-17  3:11       ` Simon Glass

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=20200529220355.4396-2-p.yadav@ti.com \
    --to=p.yadav@ti.com \
    --cc=u-boot@lists.denx.de \
    /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.