summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2016-07-19 09:27:29 +0200
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-07-19 09:27:29 +0200
commit2383050f6a3a2e00636eabfcf66445af653ddd80 (patch)
tree45e5eb04a8ac280ce36f0d1e4305c8d816ee2e70 /drivers/gpio/gpiolib.c
parentdrm/ttm: Delete an unnecessary check before the function call "ttm_tt_destroy" (diff)
parentMerge tag 'drm-vc4-next-2016-07-15' of https://github.com/anholt/linux into d... (diff)
downloadlinux-2383050f6a3a2e00636eabfcf66445af653ddd80.tar.xz
linux-2383050f6a3a2e00636eabfcf66445af653ddd80.zip
Merge remote-tracking branch 'airlied/drm-next' into topic/drm-misc
Backmerge drm-next to be able to apply Chris' connector_unregister_all cleanup (need latest i915 and sun4i state for that). Also there's a trivial conflict in ttm_bo.c that git rerere fails to remember. Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 24f60d28f0c0..570771ed19e6 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -449,7 +449,6 @@ static void gpiodevice_release(struct device *dev)
{
struct gpio_device *gdev = dev_get_drvdata(dev);
- cdev_del(&gdev->chrdev);
list_del(&gdev->list);
ida_simple_remove(&gpio_ida, gdev->id);
kfree(gdev->label);
@@ -482,7 +481,6 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
/* From this point, the .release() function cleans up gpio_device */
gdev->dev.release = gpiodevice_release;
- get_device(&gdev->dev);
pr_debug("%s: registered GPIOs %d to %d on device: %s (%s)\n",
__func__, gdev->base, gdev->base + gdev->ngpio - 1,
dev_name(&gdev->dev), gdev->chip->label ? : "generic");
@@ -770,6 +768,8 @@ void gpiochip_remove(struct gpio_chip *chip)
* be removed, else it will be dangling until the last user is
* gone.
*/
+ cdev_del(&gdev->chrdev);
+ device_del(&gdev->dev);
put_device(&gdev->dev);
}
EXPORT_SYMBOL_GPL(gpiochip_remove);
@@ -869,7 +869,7 @@ struct gpio_chip *gpiochip_find(void *data,
spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(gdev, &gpio_devices, list)
- if (match(gdev->chip, data))
+ if (gdev->chip && match(gdev->chip, data))
break;
/* No match? */
@@ -1373,8 +1373,12 @@ done:
#define VALIDATE_DESC(desc) do { \
if (!desc) \
return 0; \
+ if (IS_ERR(desc)) { \
+ pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \
+ return PTR_ERR(desc); \
+ } \
if (!desc->gdev) { \
- pr_warn("%s: invalid GPIO\n", __func__); \
+ pr_warn("%s: invalid GPIO (no device)\n", __func__); \
return -EINVAL; \
} \
if ( !desc->gdev->chip ) { \
@@ -1386,8 +1390,12 @@ done:
#define VALIDATE_DESC_VOID(desc) do { \
if (!desc) \
return; \
+ if (IS_ERR(desc)) { \
+ pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \
+ return; \
+ } \
if (!desc->gdev) { \
- pr_warn("%s: invalid GPIO\n", __func__); \
+ pr_warn("%s: invalid GPIO (no device)\n", __func__); \
return; \
} \
if (!desc->gdev->chip) { \
@@ -2056,7 +2064,14 @@ int gpiod_to_irq(const struct gpio_desc *desc)
struct gpio_chip *chip;
int offset;
- VALIDATE_DESC(desc);
+ /*
+ * Cannot VALIDATE_DESC() here as gpiod_to_irq() consumer semantics
+ * requires this function to not return zero on an invalid descriptor
+ * but rather a negative error number.
+ */
+ if (!desc || IS_ERR(desc) || !desc->gdev || !desc->gdev->chip)
+ return -EINVAL;
+
chip = desc->gdev->chip;
offset = gpio_chip_hwgpio(desc);
if (chip->to_irq) {