diff options
author | Alessandro Zummo <alessandro.zummo@towertech.it> | 2007-10-16 04:28:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:13 -0400 |
commit | d691eb901e044065de10756ea78a5758d457c7fd (patch) | |
tree | 3b166f4d54bba5677a04b885d0da52c28db3a8a3 /drivers | |
parent | 16a72c455a67bb23eed7292a31c6ba17729e78e6 (diff) |
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')
-rw-r--r-- | drivers/rtc/class.c | 1 | ||||
-rw-r--r-- | drivers/rtc/interface.c | 15 | ||||
-rw-r--r-- | drivers/rtc/rtc-dev.c | 33 |
3 files changed, 24 insertions, 25 deletions
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 10ab3b71ffc6..4dfdf019fccc 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
@@ -153,6 +153,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
153 | mutex_init(&rtc->ops_lock); | 153 | mutex_init(&rtc->ops_lock); |
154 | spin_lock_init(&rtc->irq_lock); | 154 | spin_lock_init(&rtc->irq_lock); |
155 | spin_lock_init(&rtc->irq_task_lock); | 155 | spin_lock_init(&rtc->irq_task_lock); |
156 | init_waitqueue_head(&rtc->irq_queue); | ||
156 | 157 | ||
157 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); | 158 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); |
158 | snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id); | 159 | snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id); |
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) | |||
210 | if (task == NULL || task->func == NULL) | 210 | if (task == NULL || task->func == NULL) |
211 | return -EINVAL; | 211 | return -EINVAL; |
212 | 212 | ||
213 | /* Cannot register while the char dev is in use */ | ||
214 | if (!(mutex_trylock(&rtc->char_lock))) | ||
215 | return -EBUSY; | ||
216 | |||
213 | spin_lock_irq(&rtc->irq_task_lock); | 217 | spin_lock_irq(&rtc->irq_task_lock); |
214 | if (rtc->irq_task == NULL) { | 218 | if (rtc->irq_task == NULL) { |
215 | rtc->irq_task = task; | 219 | rtc->irq_task = task; |
@@ -217,13 +221,14 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) | |||
217 | } | 221 | } |
218 | spin_unlock_irq(&rtc->irq_task_lock); | 222 | spin_unlock_irq(&rtc->irq_task_lock); |
219 | 223 | ||
224 | mutex_unlock(&rtc->char_lock); | ||
225 | |||
220 | return retval; | 226 | return retval; |
221 | } | 227 | } |
222 | EXPORT_SYMBOL_GPL(rtc_irq_register); | 228 | EXPORT_SYMBOL_GPL(rtc_irq_register); |
223 | 229 | ||
224 | void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) | 230 | void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) |
225 | { | 231 | { |
226 | |||
227 | spin_lock_irq(&rtc->irq_task_lock); | 232 | spin_lock_irq(&rtc->irq_task_lock); |
228 | if (rtc->irq_task == task) | 233 | if (rtc->irq_task == task) |
229 | rtc->irq_task = NULL; | 234 | rtc->irq_task = NULL; |
@@ -240,8 +245,10 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled | |||
240 | return -ENXIO; | 245 | return -ENXIO; |
241 | 246 | ||
242 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 247 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
248 | if (rtc->irq_task != NULL && task == NULL) | ||
249 | err = -EBUSY; | ||
243 | if (rtc->irq_task != task) | 250 | if (rtc->irq_task != task) |
244 | err = -ENXIO; | 251 | err = -EACCES; |
245 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | 252 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); |
246 | 253 | ||
247 | if (err == 0) | 254 | if (err == 0) |
@@ -260,8 +267,10 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) | |||
260 | return -ENXIO; | 267 | return -ENXIO; |
261 | 268 | ||
262 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 269 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
270 | if (rtc->irq_task != NULL && task == NULL) | ||
271 | err = -EBUSY; | ||
263 | if (rtc->irq_task != task) | 272 | if (rtc->irq_task != task) |
264 | err = -ENXIO; | 273 | err = -EACCES; |
265 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | 274 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); |
266 | 275 | ||
267 | if (err == 0) { | 276 | if (err == 0) { |
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 005fff3a3508..362400db2e8b 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c | |||
@@ -238,17 +238,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
238 | break; | 238 | break; |
239 | } | 239 | } |
240 | 240 | ||
241 | /* avoid conflicting IRQ users */ | ||
242 | if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) { | ||
243 | spin_lock_irq(&rtc->irq_task_lock); | ||
244 | if (rtc->irq_task) | ||
245 | err = -EBUSY; | ||
246 | spin_unlock_irq(&rtc->irq_task_lock); | ||
247 | |||
248 | if (err < 0) | ||
249 | return err; | ||
250 | } | ||
251 | |||
252 | /* try the driver's ioctl interface */ | 241 | /* try the driver's ioctl interface */ |
253 | if (ops->ioctl) { | 242 | if (ops->ioctl) { |
254 | err = ops->ioctl(rtc->dev.parent, cmd, arg); | 243 | err = ops->ioctl(rtc->dev.parent, cmd, arg); |
@@ -338,18 +327,20 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
338 | err = rtc_set_time(rtc, &tm); | 327 | err = rtc_set_time(rtc, &tm); |
339 | break; | 328 | break; |
340 | 329 | ||
341 | case RTC_IRQP_READ: | 330 | case RTC_PIE_ON: |
342 | if (ops->irq_set_freq) | 331 | err = rtc_irq_set_state(rtc, NULL, 1); |
343 | err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); | 332 | break; |
344 | else | 333 | |
345 | err = -ENOTTY; | 334 | case RTC_PIE_OFF: |
335 | err = rtc_irq_set_state(rtc, NULL, 0); | ||
346 | break; | 336 | break; |
347 | 337 | ||
348 | case RTC_IRQP_SET: | 338 | case RTC_IRQP_SET: |
349 | if (ops->irq_set_freq) | 339 | err = rtc_irq_set_freq(rtc, NULL, arg); |
350 | err = rtc_irq_set_freq(rtc, rtc->irq_task, arg); | 340 | break; |
351 | else | 341 | |
352 | err = -ENOTTY; | 342 | case RTC_IRQP_READ: |
343 | err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); | ||
353 | break; | 344 | break; |
354 | 345 | ||
355 | #if 0 | 346 | #if 0 |
@@ -449,8 +440,6 @@ void rtc_dev_prepare(struct rtc_device *rtc) | |||
449 | rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); | 440 | rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); |
450 | 441 | ||
451 | mutex_init(&rtc->char_lock); | 442 | mutex_init(&rtc->char_lock); |
452 | spin_lock_init(&rtc->irq_lock); | ||
453 | init_waitqueue_head(&rtc->irq_queue); | ||
454 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 443 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL |
455 | INIT_WORK(&rtc->uie_task, rtc_uie_task); | 444 | INIT_WORK(&rtc->uie_task, rtc_uie_task); |
456 | setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); | 445 | setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); |