Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alessandro Zummo and committed by
Linus Torvalds
d691eb90 16a72c45

+24 -25
+1
drivers/rtc/class.c
··· 153 153 mutex_init(&rtc->ops_lock); 154 154 spin_lock_init(&rtc->irq_lock); 155 155 spin_lock_init(&rtc->irq_task_lock); 156 + init_waitqueue_head(&rtc->irq_queue); 156 157 157 158 strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); 158 159 snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id);
+12 -3
drivers/rtc/interface.c
··· 210 210 if (task == NULL || task->func == NULL) 211 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 217 spin_lock_irq(&rtc->irq_task_lock); 214 218 if (rtc->irq_task == NULL) { 215 219 rtc->irq_task = task; ··· 221 217 } 222 218 spin_unlock_irq(&rtc->irq_task_lock); 223 219 220 + mutex_unlock(&rtc->char_lock); 221 + 224 222 return retval; 225 223 } 226 224 EXPORT_SYMBOL_GPL(rtc_irq_register); 227 225 228 226 void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) 229 227 { 230 - 231 228 spin_lock_irq(&rtc->irq_task_lock); 232 229 if (rtc->irq_task == task) 233 230 rtc->irq_task = NULL; ··· 245 240 return -ENXIO; 246 241 247 242 spin_lock_irqsave(&rtc->irq_task_lock, flags); 243 + if (rtc->irq_task != NULL && task == NULL) 244 + err = -EBUSY; 248 245 if (rtc->irq_task != task) 249 - err = -ENXIO; 246 + err = -EACCES; 250 247 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 251 248 252 249 if (err == 0) ··· 267 260 return -ENXIO; 268 261 269 262 spin_lock_irqsave(&rtc->irq_task_lock, flags); 263 + if (rtc->irq_task != NULL && task == NULL) 264 + err = -EBUSY; 270 265 if (rtc->irq_task != task) 271 - err = -ENXIO; 266 + err = -EACCES; 272 267 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 273 268 274 269 if (err == 0) {
+11 -22
drivers/rtc/rtc-dev.c
··· 238 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 241 /* try the driver's ioctl interface */ 253 242 if (ops->ioctl) { 254 243 err = ops->ioctl(rtc->dev.parent, cmd, arg); ··· 327 338 err = rtc_set_time(rtc, &tm); 328 339 break; 329 340 330 - case RTC_IRQP_READ: 331 - if (ops->irq_set_freq) 332 - err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); 333 - else 334 - err = -ENOTTY; 341 + case RTC_PIE_ON: 342 + err = rtc_irq_set_state(rtc, NULL, 1); 343 + break; 344 + 345 + case RTC_PIE_OFF: 346 + err = rtc_irq_set_state(rtc, NULL, 0); 335 347 break; 336 348 337 349 case RTC_IRQP_SET: 338 - if (ops->irq_set_freq) 339 - err = rtc_irq_set_freq(rtc, rtc->irq_task, arg); 340 - else 341 - err = -ENOTTY; 350 + err = rtc_irq_set_freq(rtc, NULL, arg); 351 + break; 352 + 353 + case RTC_IRQP_READ: 354 + err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); 342 355 break; 343 356 344 357 #if 0 ··· 440 449 rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); 441 450 442 451 mutex_init(&rtc->char_lock); 443 - spin_lock_init(&rtc->irq_lock); 444 - init_waitqueue_head(&rtc->irq_queue); 445 452 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL 446 453 INIT_WORK(&rtc->uie_task, rtc_uie_task); 447 454 setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);