summary refs log tree commit diff
path: root/drivers/rtc/interface.c
diff options
context:
space:
mode:
authorAlessandro Zummo <alessandro.zummo@towertech.it>2007-10-16 01:28:15 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 09:43:13 -0700
commitd691eb901e044065de10756ea78a5758d457c7fd (patch)
tree3b166f4d54bba5677a04b885d0da52c28db3a8a3 /drivers/rtc/interface.c
parent16a72c455a67bb23eed7292a31c6ba17729e78e6 (diff)
downloadlinux-d691eb901e044065de10756ea78a5758d457c7fd.tar.gz
RTC: periodic irq fix
Add kernel/kernel and kernel/user locking for the periodic irq feature of
the rtc class.

PIE ioctls are also supported.

Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/interface.c')
-rw-r--r--drivers/rtc/interface.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index ad66c6ecf365..a43afa54f0d7 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -210,6 +210,10 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
 	if (task == NULL || task->func == NULL)
 		return -EINVAL;
 
+	/* Cannot register while the char dev is in use */
+	if (!(mutex_trylock(&rtc->char_lock)))
+		return -EBUSY;
+
 	spin_lock_irq(&rtc->irq_task_lock);
 	if (rtc->irq_task == NULL) {
 		rtc->irq_task = task;
@@ -217,13 +221,14 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
 	}
 	spin_unlock_irq(&rtc->irq_task_lock);
 
+	mutex_unlock(&rtc->char_lock);
+
 	return retval;
 }
 EXPORT_SYMBOL_GPL(rtc_irq_register);
 
 void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
 {
-
 	spin_lock_irq(&rtc->irq_task_lock);
 	if (rtc->irq_task == task)
 		rtc->irq_task = NULL;
@@ -240,8 +245,10 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
 		return -ENXIO;
 
 	spin_lock_irqsave(&rtc->irq_task_lock, flags);
+	if (rtc->irq_task != NULL && task == NULL)
+		err = -EBUSY;
 	if (rtc->irq_task != task)
-		err = -ENXIO;
+		err = -EACCES;
 	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
 
 	if (err == 0)
@@ -260,8 +267,10 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
 		return -ENXIO;
 
 	spin_lock_irqsave(&rtc->irq_task_lock, flags);
+	if (rtc->irq_task != NULL && task == NULL)
+		err = -EBUSY;
 	if (rtc->irq_task != task)
-		err = -ENXIO;
+		err = -EACCES;
 	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
 
 	if (err == 0) {