diff options
Diffstat (limited to 'drivers/rtc/interface.c')
| -rw-r--r-- | drivers/rtc/interface.c | 206 |
1 files changed, 202 insertions, 4 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 925006d3310..8ec6b069a7f 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
| @@ -116,6 +116,186 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) | |||
| 116 | } | 116 | } |
| 117 | EXPORT_SYMBOL_GPL(rtc_set_mmss); | 117 | EXPORT_SYMBOL_GPL(rtc_set_mmss); |
| 118 | 118 | ||
| 119 | static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | ||
| 120 | { | ||
| 121 | int err; | ||
| 122 | |||
| 123 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
| 124 | if (err) | ||
| 125 | return err; | ||
| 126 | |||
| 127 | if (rtc->ops == NULL) | ||
| 128 | err = -ENODEV; | ||
| 129 | else if (!rtc->ops->read_alarm) | ||
| 130 | err = -EINVAL; | ||
| 131 | else { | ||
| 132 | memset(alarm, 0, sizeof(struct rtc_wkalrm)); | ||
| 133 | err = rtc->ops->read_alarm(rtc->dev.parent, alarm); | ||
| 134 | } | ||
| 135 | |||
| 136 | mutex_unlock(&rtc->ops_lock); | ||
| 137 | return err; | ||
| 138 | } | ||
| 139 | |||
| 140 | int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | ||
| 141 | { | ||
| 142 | int err; | ||
| 143 | struct rtc_time before, now; | ||
| 144 | int first_time = 1; | ||
| 145 | unsigned long t_now, t_alm; | ||
| 146 | enum { none, day, month, year } missing = none; | ||
| 147 | unsigned days; | ||
| 148 | |||
| 149 | /* The lower level RTC driver may return -1 in some fields, | ||
| 150 | * creating invalid alarm->time values, for reasons like: | ||
| 151 | * | ||
| 152 | * - The hardware may not be capable of filling them in; | ||
| 153 | * many alarms match only on time-of-day fields, not | ||
| 154 | * day/month/year calendar data. | ||
| 155 | * | ||
| 156 | * - Some hardware uses illegal values as "wildcard" match | ||
| 157 | * values, which non-Linux firmware (like a BIOS) may try | ||
| 158 | * to set up as e.g. "alarm 15 minutes after each hour". | ||
| 159 | * Linux uses only oneshot alarms. | ||
| 160 | * | ||
| 161 | * When we see that here, we deal with it by using values from | ||
| 162 | * a current RTC timestamp for any missing (-1) values. The | ||
| 163 | * RTC driver prevents "periodic alarm" modes. | ||
| 164 | * | ||
| 165 | * But this can be racey, because some fields of the RTC timestamp | ||
| 166 | * may have wrapped in the interval since we read the RTC alarm, | ||
| 167 | * which would lead to us inserting inconsistent values in place | ||
| 168 | * of the -1 fields. | ||
| 169 | * | ||
| 170 | * Reading the alarm and timestamp in the reverse sequence | ||
| 171 | * would have the same race condition, and not solve the issue. | ||
| 172 | * | ||
| 173 | * So, we must first read the RTC timestamp, | ||
| 174 | * then read the RTC alarm value, | ||
| 175 | * and then read a second RTC timestamp. | ||
| 176 | * | ||
| 177 | * If any fields of the second timestamp have changed | ||
| 178 | * when compared with the first timestamp, then we know | ||
| 179 | * our timestamp may be inconsistent with that used by | ||
| 180 | * the low-level rtc_read_alarm_internal() function. | ||
| 181 | * | ||
| 182 | * So, when the two timestamps disagree, we just loop and do | ||
| 183 | * the process again to get a fully consistent set of values. | ||
| 184 | * | ||
| 185 | * This could all instead be done in the lower level driver, | ||
| 186 | * but since more than one lower level RTC implementation needs it, | ||
| 187 | * then it's probably best best to do it here instead of there.. | ||
| 188 | */ | ||
| 189 | |||
| 190 | /* Get the "before" timestamp */ | ||
| 191 | err = rtc_read_time(rtc, &before); | ||
| 192 | if (err < 0) | ||
| 193 | return err; | ||
| 194 | do { | ||
| 195 | if (!first_time) | ||
| 196 | memcpy(&before, &now, sizeof(struct rtc_time)); | ||
| 197 | first_time = 0; | ||
| 198 | |||
| 199 | /* get the RTC alarm values, which may be incomplete */ | ||
| 200 | err = rtc_read_alarm_internal(rtc, alarm); | ||
| 201 | if (err) | ||
| 202 | return err; | ||
| 203 | |||
| 204 | /* full-function RTCs won't have such missing fields */ | ||
| 205 | if (rtc_valid_tm(&alarm->time) == 0) | ||
| 206 | return 0; | ||
| 207 | |||
| 208 | /* get the "after" timestamp, to detect wrapped fields */ | ||
| 209 | err = rtc_read_time(rtc, &now); | ||
| 210 | if (err < 0) | ||
| 211 | return err; | ||
| 212 | |||
| 213 | /* note that tm_sec is a "don't care" value here: */ | ||
| 214 | } while ( before.tm_min != now.tm_min | ||
| 215 | || before.tm_hour != now.tm_hour | ||
| 216 | || before.tm_mon != now.tm_mon | ||
| 217 | || before.tm_year != now.tm_year); | ||
| 218 | |||
| 219 | /* Fill in the missing alarm fields using the timestamp; we | ||
| 220 | * know there's at least one since alarm->time is invalid. | ||
| 221 | */ | ||
| 222 | if (alarm->time.tm_sec == -1) | ||
| 223 | alarm->time.tm_sec = now.tm_sec; | ||
| 224 | if (alarm->time.tm_min == -1) | ||
| 225 | alarm->time.tm_min = now.tm_min; | ||
| 226 | if (alarm->time.tm_hour == -1) | ||
| 227 | alarm->time.tm_hour = now.tm_hour; | ||
| 228 | |||
| 229 | /* For simplicity, only support date rollover for now */ | ||
| 230 | if (alarm->time.tm_mday == -1) { | ||
| 231 | alarm->time.tm_mday = now.tm_mday; | ||
| 232 | missing = day; | ||
| 233 | } | ||
| 234 | if (alarm->time.tm_mon == -1) { | ||
| 235 | alarm->time.tm_mon = now.tm_mon; | ||
| 236 | if (missing == none) | ||
| 237 | missing = month; | ||
| 238 | } | ||
| 239 | if (alarm->time.tm_year == -1) { | ||
| 240 | alarm->time.tm_year = now.tm_year; | ||
| 241 | if (missing == none) | ||
| 242 | missing = year; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* with luck, no rollover is needed */ | ||
| 246 | rtc_tm_to_time(&now, &t_now); | ||
| 247 | rtc_tm_to_time(&alarm->time, &t_alm); | ||
| 248 | if (t_now < t_alm) | ||
| 249 | goto done; | ||
| 250 | |||
| 251 | switch (missing) { | ||
| 252 | |||
| 253 | /* 24 hour rollover ... if it's now 10am Monday, an alarm that | ||
| 254 | * that will trigger at 5am will do so at 5am Tuesday, which | ||
| 255 | * could also be in the next month or year. This is a common | ||
| 256 | * case, especially for PCs. | ||
| 257 | */ | ||
| 258 | case day: | ||
| 259 | dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day"); | ||
| 260 | t_alm += 24 * 60 * 60; | ||
| 261 | rtc_time_to_tm(t_alm, &alarm->time); | ||
| 262 | break; | ||
| 263 | |||
| 264 | /* Month rollover ... if it's the 31th, an alarm on the 3rd will | ||
| 265 | * be next month. An alarm matching on the 30th, 29th, or 28th | ||
| 266 | * may end up in the month after that! Many newer PCs support | ||
| 267 | * this type of alarm. | ||
| 268 | */ | ||
| 269 | case month: | ||
| 270 | dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month"); | ||
| 271 | do { | ||
| 272 | if (alarm->time.tm_mon < 11) | ||
| 273 | alarm->time.tm_mon++; | ||
| 274 | else { | ||
| 275 | alarm->time.tm_mon = 0; | ||
| 276 | alarm->time.tm_year++; | ||
| 277 | } | ||
| 278 | days = rtc_month_days(alarm->time.tm_mon, | ||
| 279 | alarm->time.tm_year); | ||
| 280 | } while (days < alarm->time.tm_mday); | ||
| 281 | break; | ||
| 282 | |||
| 283 | /* Year rollover ... easy except for leap years! */ | ||
| 284 | case year: | ||
| 285 | dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year"); | ||
| 286 | do { | ||
| 287 | alarm->time.tm_year++; | ||
| 288 | } while (rtc_valid_tm(&alarm->time) != 0); | ||
| 289 | break; | ||
| 290 | |||
| 291 | default: | ||
| 292 | dev_warn(&rtc->dev, "alarm rollover not handled\n"); | ||
| 293 | } | ||
| 294 | |||
| 295 | done: | ||
| 296 | return 0; | ||
| 297 | } | ||
| 298 | |||
| 119 | int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 299 | int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
| 120 | { | 300 | { |
| 121 | int err; | 301 | int err; |
| @@ -209,9 +389,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
| 209 | } | 389 | } |
| 210 | 390 | ||
| 211 | if (err) | 391 | if (err) |
| 212 | return err; | 392 | /* nothing */; |
| 213 | 393 | else if (!rtc->ops) | |
| 214 | if (!rtc->ops) | ||
| 215 | err = -ENODEV; | 394 | err = -ENODEV; |
| 216 | else if (!rtc->ops->alarm_irq_enable) | 395 | else if (!rtc->ops->alarm_irq_enable) |
| 217 | err = -EINVAL; | 396 | err = -EINVAL; |
| @@ -229,6 +408,12 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
| 229 | if (err) | 408 | if (err) |
| 230 | return err; | 409 | return err; |
| 231 | 410 | ||
| 411 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | ||
| 412 | if (enabled == 0 && rtc->uie_irq_active) { | ||
| 413 | mutex_unlock(&rtc->ops_lock); | ||
| 414 | return rtc_dev_update_irq_enable_emul(rtc, 0); | ||
| 415 | } | ||
| 416 | #endif | ||
| 232 | /* make sure we're changing state */ | 417 | /* make sure we're changing state */ |
| 233 | if (rtc->uie_rtctimer.enabled == enabled) | 418 | if (rtc->uie_rtctimer.enabled == enabled) |
| 234 | goto out; | 419 | goto out; |
| @@ -248,6 +433,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
| 248 | 433 | ||
| 249 | out: | 434 | out: |
| 250 | mutex_unlock(&rtc->ops_lock); | 435 | mutex_unlock(&rtc->ops_lock); |
| 436 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | ||
| 437 | /* | ||
| 438 | * Enable emulation if the driver did not provide | ||
| 439 | * the update_irq_enable function pointer or if returned | ||
| 440 | * -EINVAL to signal that it has been configured without | ||
| 441 | * interrupts or that are not available at the moment. | ||
| 442 | */ | ||
| 443 | if (err == -EINVAL) | ||
| 444 | err = rtc_dev_update_irq_enable_emul(rtc, enabled); | ||
| 445 | #endif | ||
| 251 | return err; | 446 | return err; |
| 252 | 447 | ||
| 253 | } | 448 | } |
| @@ -263,7 +458,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable); | |||
| 263 | * | 458 | * |
| 264 | * Triggers the registered irq_task function callback. | 459 | * Triggers the registered irq_task function callback. |
| 265 | */ | 460 | */ |
| 266 | static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) | 461 | void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) |
| 267 | { | 462 | { |
| 268 | unsigned long flags; | 463 | unsigned long flags; |
| 269 | 464 | ||
| @@ -464,6 +659,9 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) | |||
| 464 | int err = 0; | 659 | int err = 0; |
| 465 | unsigned long flags; | 660 | unsigned long flags; |
| 466 | 661 | ||
| 662 | if (freq <= 0) | ||
| 663 | return -EINVAL; | ||
| 664 | |||
| 467 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 665 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
| 468 | if (rtc->irq_task != NULL && task == NULL) | 666 | if (rtc->irq_task != NULL && task == NULL) |
| 469 | err = -EBUSY; | 667 | err = -EBUSY; |
