rtc: cmos: Do not export alarm rtc_ops when we do not support alarms

When there is no IRQ configured for the RTC, the rtc-cmos code does not
support alarms, all alarm rtc_ops fail with -EIO / -EINVAL.

The rtc-core expects a rtc driver which does not support rtc alarms to
not have alarm ops at all. Otherwise the wakealarm sysfs attr will read
as empty rather then returning an error, making it impossible for
userspace to find out beforehand if alarms are supported.

A system without an IRQ for the RTC before this patch:
[root@localhost ~]# cat /sys/class/rtc/rtc0/wakealarm
[root@localhost ~]#

After this patch:
[root@localhost ~]# cat /sys/class/rtc/rtc0/wakealarm
cat: /sys/class/rtc/rtc0/wakealarm: No such file or directory
[root@localhost ~]#

This fixes gnome-session + systemd trying to use suspend-then-hibernate,
which causes systemd to abort the suspend when writing the RTC alarm fails.

BugLink: https://github.com/systemd/systemd/issues/9988
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
Hans de Goede 2018-09-04 16:51:29 +02:00 коммит произвёл Alexandre Belloni
Родитель 651022382c
Коммит fbb974ba69
1 изменённых файлов: 12 добавлений и 4 удалений

Просмотреть файл

@ -257,6 +257,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
struct cmos_rtc *cmos = dev_get_drvdata(dev); struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char rtc_control; unsigned char rtc_control;
/* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq)) if (!is_valid_irq(cmos->irq))
return -EIO; return -EIO;
@ -452,6 +453,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
unsigned char mon, mday, hrs, min, sec, rtc_control; unsigned char mon, mday, hrs, min, sec, rtc_control;
int ret; int ret;
/* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq)) if (!is_valid_irq(cmos->irq))
return -EIO; return -EIO;
@ -516,9 +518,6 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
struct cmos_rtc *cmos = dev_get_drvdata(dev); struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned long flags; unsigned long flags;
if (!is_valid_irq(cmos->irq))
return -EINVAL;
spin_lock_irqsave(&rtc_lock, flags); spin_lock_irqsave(&rtc_lock, flags);
if (enabled) if (enabled)
@ -579,6 +578,12 @@ static const struct rtc_class_ops cmos_rtc_ops = {
.alarm_irq_enable = cmos_alarm_irq_enable, .alarm_irq_enable = cmos_alarm_irq_enable,
}; };
static const struct rtc_class_ops cmos_rtc_ops_no_alarm = {
.read_time = cmos_read_time,
.set_time = cmos_set_time,
.proc = cmos_procfs,
};
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
/* /*
@ -855,9 +860,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
goto cleanup1; goto cleanup1;
} }
cmos_rtc.rtc->ops = &cmos_rtc_ops;
} else {
cmos_rtc.rtc->ops = &cmos_rtc_ops_no_alarm;
} }
cmos_rtc.rtc->ops = &cmos_rtc_ops;
cmos_rtc.rtc->nvram_old_abi = true; cmos_rtc.rtc->nvram_old_abi = true;
retval = rtc_register_device(cmos_rtc.rtc); retval = rtc_register_device(cmos_rtc.rtc);
if (retval) if (retval)