aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2010-11-18 17:08:38 -0500
committerAnton Vorontsov <cbouatmailru@gmail.com>2010-12-21 18:39:45 -0500
commit26eb387265872b59566ddeed5e9bf142a6b9ff5b (patch)
tree7c1131870916aaf5cebb2d5e5d60c998de4844ba
parent80577b8a478f3386d106464f2a2241b2d43571ce (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>
-rw-r--r--drivers/power/gpio-charger.c29
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
139err_irq_free:
140 if (gpio_charger->irq)
141 free_irq(gpio_charger->irq, charger);
142err_gpio_free: 140err_gpio_free:
143 gpio_free(pdata->gpio); 141 gpio_free(pdata->gpio);
144err_free: 142err_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);