usb: common: usb-conn-gpio: fix NULL pointer dereference of charger
authorChunfeng Yun <chunfeng.yun@mediatek.com>
Wed, 19 May 2021 06:39:44 +0000 (14:39 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 21 May 2021 12:09:54 +0000 (14:09 +0200)
When power on system with OTG cable, IDDIG's interrupt arises before
the charger registration, it will cause a NULL pointer dereference,
fix the issue by registering the power supply before requesting
IDDIG/VBUS irq.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/1621406386-18838-1-git-send-email-chunfeng.yun@mediatek.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/common/usb-conn-gpio.c

index 6c4e3a1..c9545a4 100644 (file)
@@ -149,14 +149,32 @@ static int usb_charger_get_property(struct power_supply *psy,
        return 0;
 }
 
-static int usb_conn_probe(struct platform_device *pdev)
+static int usb_conn_psy_register(struct usb_conn_info *info)
 {
-       struct device *dev = &pdev->dev;
-       struct power_supply_desc *desc;
-       struct usb_conn_info *info;
+       struct device *dev = info->dev;
+       struct power_supply_desc *desc = &info->desc;
        struct power_supply_config cfg = {
                .of_node = dev->of_node,
        };
+
+       desc->name = "usb-charger";
+       desc->properties = usb_charger_properties;
+       desc->num_properties = ARRAY_SIZE(usb_charger_properties);
+       desc->get_property = usb_charger_get_property;
+       desc->type = POWER_SUPPLY_TYPE_USB;
+       cfg.drv_data = info;
+
+       info->charger = devm_power_supply_register(dev, desc, &cfg);
+       if (IS_ERR(info->charger))
+               dev_err(dev, "Unable to register charger\n");
+
+       return PTR_ERR_OR_ZERO(info->charger);
+}
+
+static int usb_conn_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct usb_conn_info *info;
        bool need_vbus = true;
        int ret = 0;
 
@@ -218,6 +236,10 @@ static int usb_conn_probe(struct platform_device *pdev)
                return PTR_ERR(info->role_sw);
        }
 
+       ret = usb_conn_psy_register(info);
+       if (ret)
+               goto put_role_sw;
+
        if (info->id_gpiod) {
                info->id_irq = gpiod_to_irq(info->id_gpiod);
                if (info->id_irq < 0) {
@@ -252,20 +274,6 @@ static int usb_conn_probe(struct platform_device *pdev)
                }
        }
 
-       desc = &info->desc;
-       desc->name = "usb-charger";
-       desc->properties = usb_charger_properties;
-       desc->num_properties = ARRAY_SIZE(usb_charger_properties);
-       desc->get_property = usb_charger_get_property;
-       desc->type = POWER_SUPPLY_TYPE_USB;
-       cfg.drv_data = info;
-
-       info->charger = devm_power_supply_register(dev, desc, &cfg);
-       if (IS_ERR(info->charger)) {
-               dev_err(dev, "Unable to register charger\n");
-               return PTR_ERR(info->charger);
-       }
-
        platform_set_drvdata(pdev, info);
 
        /* Perform initial detection */