|
@@ -325,14 +325,86 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
|
|
|
cmos_checkintr(cmos, rtc_control);
|
|
|
}
|
|
|
|
|
|
+static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|
|
+{
|
|
|
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
|
|
+ struct rtc_time now;
|
|
|
+
|
|
|
+ cmos_read_time(dev, &now);
|
|
|
+
|
|
|
+ if (!cmos->day_alrm) {
|
|
|
+ time64_t t_max_date;
|
|
|
+ time64_t t_alrm;
|
|
|
+
|
|
|
+ t_max_date = rtc_tm_to_time64(&now);
|
|
|
+ t_max_date += 24 * 60 * 60 - 1;
|
|
|
+ t_alrm = rtc_tm_to_time64(&t->time);
|
|
|
+ if (t_alrm > t_max_date) {
|
|
|
+ dev_err(dev,
|
|
|
+ "Alarms can be up to one day in the future\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ } else if (!cmos->mon_alrm) {
|
|
|
+ struct rtc_time max_date = now;
|
|
|
+ time64_t t_max_date;
|
|
|
+ time64_t t_alrm;
|
|
|
+ int max_mday;
|
|
|
+
|
|
|
+ if (max_date.tm_mon == 11) {
|
|
|
+ max_date.tm_mon = 0;
|
|
|
+ max_date.tm_year += 1;
|
|
|
+ } else {
|
|
|
+ max_date.tm_mon += 1;
|
|
|
+ }
|
|
|
+ max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
|
|
|
+ if (max_date.tm_mday > max_mday)
|
|
|
+ max_date.tm_mday = max_mday;
|
|
|
+
|
|
|
+ t_max_date = rtc_tm_to_time64(&max_date);
|
|
|
+ t_max_date -= 1;
|
|
|
+ t_alrm = rtc_tm_to_time64(&t->time);
|
|
|
+ if (t_alrm > t_max_date) {
|
|
|
+ dev_err(dev,
|
|
|
+ "Alarms can be up to one month in the future\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ struct rtc_time max_date = now;
|
|
|
+ time64_t t_max_date;
|
|
|
+ time64_t t_alrm;
|
|
|
+ int max_mday;
|
|
|
+
|
|
|
+ max_date.tm_year += 1;
|
|
|
+ max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
|
|
|
+ if (max_date.tm_mday > max_mday)
|
|
|
+ max_date.tm_mday = max_mday;
|
|
|
+
|
|
|
+ t_max_date = rtc_tm_to_time64(&max_date);
|
|
|
+ t_max_date -= 1;
|
|
|
+ t_alrm = rtc_tm_to_time64(&t->time);
|
|
|
+ if (t_alrm > t_max_date) {
|
|
|
+ dev_err(dev,
|
|
|
+ "Alarms can be up to one year in the future\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|
|
{
|
|
|
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
|
|
unsigned char mon, mday, hrs, min, sec, rtc_control;
|
|
|
+ int ret;
|
|
|
|
|
|
if (!is_valid_irq(cmos->irq))
|
|
|
return -EIO;
|
|
|
|
|
|
+ ret = cmos_validate_alarm(dev, t);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
mon = t->time.tm_mon + 1;
|
|
|
mday = t->time.tm_mday;
|
|
|
hrs = t->time.tm_hour;
|