aboutsummaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2010-05-08 19:19:51 +0200
committerLars-Peter Clausen <lars@metafoo.de>2010-05-17 19:59:40 +0200
commit501a67c8d153ad5849fc47720598fa2c4c05144b (patch)
tree1531527e773462372972e939d575532f6a201a2d /drivers/mfd
parent470379585be3e2e116e9412e114698debb02eb9e (diff)
MFD: pcf50633-adc: Fix potential race pcf50633_adc_sync_read
Currently it's not guaranteed that request struct is not already freed when reading from it. Fix this by moving synced request related fields from the pcf50633_adc_request struct to its own struct and store it on the functions stack. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/pcf50633-adc.c39
1 files changed, 15 insertions, 24 deletions
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c
index fe8f922f665..aed0d2a9b03 100644
--- a/drivers/mfd/pcf50633-adc.c
+++ b/drivers/mfd/pcf50633-adc.c
@@ -30,13 +30,13 @@
struct pcf50633_adc_request {
int mux;
int avg;
- int result;
void (*callback)(struct pcf50633 *, void *, int);
void *callback_param;
+};
- /* Used in case of sync requests */
+struct pcf50633_adc_sync_request {
+ int result;
struct completion completion;
-
};
#define PCF50633_MAX_ADC_FIFO_DEPTH 8
@@ -109,10 +109,10 @@ adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req)
return 0;
}
-static void
-pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result)
+static void pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param,
+ int result)
{
- struct pcf50633_adc_request *req = param;
+ struct pcf50633_adc_sync_request *req = param;
req->result = result;
complete(&req->completion);
@@ -120,28 +120,19 @@ pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result)
int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg)
{
- struct pcf50633_adc_request *req;
- int err;
+ struct pcf50633_adc_sync_request req;
+ int ret;
- /* req is freed when the result is ready, in interrupt handler */
- req = kzalloc(sizeof(*req), GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
- req->mux = mux;
- req->avg = avg;
- req->callback = pcf50633_adc_sync_read_callback;
- req->callback_param = req;
+ init_completion(&req.completion);
- init_completion(&req->completion);
- err = adc_enqueue_request(pcf, req);
- if (err)
- return err;
+ ret = pcf50633_adc_async_read(pcf, mux, avg,
+ pcf50633_adc_sync_read_callback, &req);
+ if (ret)
+ return ret;
- wait_for_completion(&req->completion);
+ wait_for_completion(&req.completion);
- /* FIXME by this time req might be already freed */
- return req->result;
+ return req.result;
}
EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read);