diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2010-11-18 17:08:38 -0500 |
---|---|---|
committer | Anton Vorontsov <cbouatmailru@gmail.com> | 2010-12-21 18:39:45 -0500 |
commit | 26eb387265872b59566ddeed5e9bf142a6b9ff5b (patch) | |
tree | 7c1131870916aaf5cebb2d5e5d60c998de4844ba /drivers/power | |
parent | 80577b8a478f3386d106464f2a2241b2d43571ce (diff) |
gpio-charger: Fix potential race between irq handler and probe/remove
This patch fixes a potential race between the irq handler and the probe
and remove functions.
The irq should not be requested before the chargers power_supply has been
registered and has to be freed before the power_supply is unregistered,
otherwise it is possible that the irq fires while the power_supply is not
initialized yet or has already been freed.
While we are at it replace request_irq with request_any_context_irq.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/gpio-charger.c | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index 43078e34428a..25b88ac1d44c 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c | |||
@@ -98,7 +98,7 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev) | |||
98 | charger->type = pdata->type; | 98 | charger->type = pdata->type; |
99 | charger->properties = gpio_charger_properties; | 99 | charger->properties = gpio_charger_properties; |
100 | charger->num_properties = ARRAY_SIZE(gpio_charger_properties); | 100 | charger->num_properties = ARRAY_SIZE(gpio_charger_properties); |
101 | charger->get_property = gpio_charger_get_property; | 101 | charger->get_property = gpio_charger_get_property; |
102 | charger->supplied_to = pdata->supplied_to; | 102 | charger->supplied_to = pdata->supplied_to; |
103 | charger->num_supplicants = pdata->num_supplicants; | 103 | charger->num_supplicants = pdata->num_supplicants; |
104 | 104 | ||
@@ -113,9 +113,18 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev) | |||
113 | goto err_gpio_free; | 113 | goto err_gpio_free; |
114 | } | 114 | } |
115 | 115 | ||
116 | gpio_charger->pdata = pdata; | ||
117 | |||
118 | ret = power_supply_register(&pdev->dev, charger); | ||
119 | if (ret < 0) { | ||
120 | dev_err(&pdev->dev, "Failed to register power supply: %d\n", | ||
121 | ret); | ||
122 | goto err_gpio_free; | ||
123 | } | ||
124 | |||
116 | irq = gpio_to_irq(pdata->gpio); | 125 | irq = gpio_to_irq(pdata->gpio); |
117 | if (irq > 0) { | 126 | if (irq > 0) { |
118 | ret = request_irq(irq, gpio_charger_irq, | 127 | ret = request_any_context_irq(irq, gpio_charger_irq, |
119 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 128 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
120 | dev_name(&pdev->dev), charger); | 129 | dev_name(&pdev->dev), charger); |
121 | if (ret) | 130 | if (ret) |
@@ -124,21 +133,10 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev) | |||
124 | gpio_charger->irq = irq; | 133 | gpio_charger->irq = irq; |
125 | } | 134 | } |
126 | 135 | ||
127 | gpio_charger->pdata = pdata; | ||
128 | |||
129 | ret = power_supply_register(&pdev->dev, charger); | ||
130 | if (ret < 0) { | ||
131 | dev_err(&pdev->dev, "Failed to register power supply: %d\n", ret); | ||
132 | goto err_irq_free; | ||
133 | } | ||
134 | |||
135 | platform_set_drvdata(pdev, gpio_charger); | 136 | platform_set_drvdata(pdev, gpio_charger); |
136 | 137 | ||
137 | return 0; | 138 | return 0; |
138 | 139 | ||
139 | err_irq_free: | ||
140 | if (gpio_charger->irq) | ||
141 | free_irq(gpio_charger->irq, charger); | ||
142 | err_gpio_free: | 140 | err_gpio_free: |
143 | gpio_free(pdata->gpio); | 141 | gpio_free(pdata->gpio); |
144 | err_free: | 142 | err_free: |
@@ -150,10 +148,11 @@ static int __devexit gpio_charger_remove(struct platform_device *pdev) | |||
150 | { | 148 | { |
151 | struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); | 149 | struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); |
152 | 150 | ||
153 | power_supply_unregister(&gpio_charger->charger); | ||
154 | |||
155 | if (gpio_charger->irq) | 151 | if (gpio_charger->irq) |
156 | free_irq(gpio_charger->irq, &gpio_charger->charger); | 152 | free_irq(gpio_charger->irq, &gpio_charger->charger); |
153 | |||
154 | power_supply_unregister(&gpio_charger->charger); | ||
155 | |||
157 | gpio_free(gpio_charger->pdata->gpio); | 156 | gpio_free(gpio_charger->pdata->gpio); |
158 | 157 | ||
159 | platform_set_drvdata(pdev, NULL); | 158 | platform_set_drvdata(pdev, NULL); |