From 4c014e872e02baa5b0bde38b2b2867ccf1f9df76 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 5 Mar 2010 13:44:30 -0800 Subject: rtc/mc13783: protect rtc {,un}registration by mc13783 lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to protect from interrupt handlers using an unregistered rtc device. To assert that the reset irq is considered now before the rtc is registered the corresponding status is checked before. Signed-off-by: Uwe Kleine-König Cc: Alessandro Zummo Cc: Paul Gortmaker Cc: Valentin Longchamp Cc: Sascha Hauer Cc: Samuel Ortiz Cc: Dmitry Torokhov Cc: Luotao Fu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mc13783.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c index 0a978a0e40fc..6a36201178a8 100644 --- a/drivers/rtc/rtc-mc13783.c +++ b/drivers/rtc/rtc-mc13783.c @@ -169,6 +169,7 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) { int ret; struct mc13783_rtc *priv; + int rtcrst_pending; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -177,8 +178,6 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) priv->mc13783 = dev_get_drvdata(pdev->dev.parent); platform_set_drvdata(pdev, priv); - priv->valid = 1; - mc13783_lock(priv->mc13783); ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST, @@ -186,33 +185,37 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) if (ret) goto err_reset_irq_request; + ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_RTCRST, + NULL, &rtcrst_pending); + if (ret) + goto err_reset_irq_status; + + priv->valid = !rtcrst_pending; + ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ, mc13783_rtc_update_handler, DRIVER_NAME, priv); if (ret) goto err_update_irq_request; - mc13783_unlock(priv->mc13783); - priv->rtc = rtc_device_register(pdev->name, &pdev->dev, &mc13783_rtc_ops, THIS_MODULE); - if (IS_ERR(priv->rtc)) { ret = PTR_ERR(priv->rtc); - mc13783_lock(priv->mc13783); - mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); err_update_irq_request: +err_reset_irq_status: + mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); err_reset_irq_request: - mc13783_unlock(priv->mc13783); - platform_set_drvdata(pdev, NULL); kfree(priv); } + mc13783_unlock(priv->mc13783); + return ret; } @@ -220,10 +223,10 @@ static int __devexit mc13783_rtc_remove(struct platform_device *pdev) { struct mc13783_rtc *priv = platform_get_drvdata(pdev); - rtc_device_unregister(priv->rtc); - mc13783_lock(priv->mc13783); + rtc_device_unregister(priv->rtc); + mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); -- cgit v1.2.3-58-ga151