* [PATCH] add rtc platform driver for EFI
@ 2009-01-09 0:56 dann frazier
2009-01-09 2:27 ` [rtc-linux] " Alessandro Zummo
0 siblings, 1 reply; 16+ messages in thread
From: dann frazier @ 2009-01-09 0:56 UTC (permalink / raw)
To: rtc-linux, linux-ia64; +Cc: linux-kernel
Munge Stephane Eranian's efirtc.c code into an rtc platform driver
Signed-off-by: dann frazier <dannf@hp.com>
---
arch/ia64/kernel/time.c | 18 +++
drivers/rtc/Kconfig | 10 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-efi.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 323 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-efi.c
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index f0ebb34..9ed5ba0 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -20,6 +20,7 @@
#include <linux/efi.h>
#include <linux/timex.h>
#include <linux/clocksource.h>
+#include <linux/platform_device.h>
#include <asm/machvec.h>
#include <asm/delay.h>
@@ -405,6 +406,23 @@ static struct irqaction timer_irqaction = {
.name = "timer"
};
+struct platform_device rtc_efi_dev = {
+ .name = "rtc-efi",
+ .id = -1,
+};
+
+static int __init rtc_init(void)
+{
+ int ret;
+ ret = platform_device_register(&rtc_efi_dev);
+ if (ret < 0)
+ printk(KERN_ERR "unable to register rtc device...\n");
+
+ /* not necessarily an error */
+ return 0;
+}
+module_init(rtc_init);
+
void __init
time_init (void)
{
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 165a818..37ce842 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -433,6 +433,16 @@ config RTC_DRV_DS1742
This driver can also be built as a module. If so, the module
will be called rtc-ds1742.
+config RTC_DRV_EFI
+ tristate "EFI RTC"
+ depends on IA64
+ help
+ If you say yes here you will get support for the EFI
+ Real Time Clock.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-efi.
+
config RTC_DRV_STK17TA8
tristate "Simtek STK17TA8"
depends on RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6e79c91..29db401 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
+obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
new file mode 100644
index 0000000..2386da0
--- /dev/null
+++ b/drivers/rtc/rtc-efi.c
@@ -0,0 +1,294 @@
+/*
+ * rtc-efi: RTC Class Driver for EFI-based systems
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Author: dann frazier <dannf@hp.com>
+ * Based on efirtc.c by Stephane Eranian
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+
+#include <linux/efi.h>
+
+#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
+/*
+ * EFI Epoch is 1/1/1998
+ */
+#define EFI_RTC_EPOCH 1998
+
+#define is_leap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+struct efi_rtc {
+ struct rtc_device *rtc;
+ spinlock_t lock;
+};
+
+static const unsigned short int __mon_yday[2][13] =
+{
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
+/*
+ * returns day of the year [0-365]
+ */
+static inline int
+compute_yday(efi_time_t *eft)
+{
+ /* efi_time_t.month is in the [1-12] so, we need -1 */
+ return __mon_yday[is_leap(eft->year)][eft->month-1] + eft->day - 1;
+}
+/*
+ * returns day of the week [0-6] 0=Sunday
+ *
+ * Don't try to provide a year that's before 1998, please !
+ */
+static int
+compute_wday(efi_time_t *eft)
+{
+ int y;
+ int ndays = 0;
+
+ if (eft->year < 1998) {
+ printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+ return -1;
+ }
+
+ for (y = EFI_RTC_EPOCH; y < eft->year; y++)
+ ndays += 365 + (is_leap(y) ? 1 : 0);
+
+ ndays += compute_yday(eft);
+
+ /*
+ * 4=1/1/1998 was a Thursday
+ */
+ return (ndays + 4) % 7;
+}
+
+static void
+convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
+{
+
+ eft->year = wtime->tm_year + 1900;
+ eft->month = wtime->tm_mon + 1;
+ eft->day = wtime->tm_mday;
+ eft->hour = wtime->tm_hour;
+ eft->minute = wtime->tm_min;
+ eft->second = wtime->tm_sec;
+ eft->nanosecond = 0;
+ eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
+ eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
+}
+
+static void
+convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
+{
+ memset(wtime, 0, sizeof(*wtime));
+ wtime->tm_sec = eft->second;
+ wtime->tm_min = eft->minute;
+ wtime->tm_hour = eft->hour;
+ wtime->tm_mday = eft->day;
+ wtime->tm_mon = eft->month - 1;
+ wtime->tm_year = eft->year - 1900;
+
+ /* day of the week [0-6], Sunday=0 */
+ wtime->tm_wday = compute_wday(eft);
+
+ /* day in the year [1-365]*/
+ wtime->tm_yday = compute_yday(eft);
+
+
+ switch (eft->daylight & EFI_ISDST) {
+ case EFI_ISDST:
+ wtime->tm_isdst = 1;
+ break;
+ case EFI_TIME_ADJUST_DAYLIGHT:
+ wtime->tm_isdst = 0;
+ break;
+ default:
+ wtime->tm_isdst = -1;
+ }
+}
+
+static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct efi_rtc *p = dev_get_drvdata(dev);
+ efi_time_t eft;
+ efi_status_t status;
+ unsigned long flags;
+
+ lock_kernel();
+
+ spin_lock_irqsave(&p->lock, flags);
+ /*
+ * As of EFI v1.10, this call always returns an unsupported status
+ */
+ status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
+ (efi_bool_t *)&wkalrm->pending, &eft);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ unlock_kernel();
+
+ if (status != EFI_SUCCESS)
+ return -EINVAL;
+
+ convert_from_efi_time(&eft, &wkalrm->time);
+
+ return 0;
+}
+
+static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct efi_rtc *p = dev_get_drvdata(dev);
+ efi_time_t eft;
+ efi_status_t status;
+ unsigned long flags;
+
+ convert_to_efi_time(&wkalrm->time, &eft);
+
+ lock_kernel();
+
+ spin_lock_irqsave(&p->lock, flags);
+ /*
+ * XXX Fixme:
+ * As of EFI 0.92 with the firmware I have on my
+ * machine this call does not seem to work quite
+ * right
+ *
+ * As of v1.10, this call always returns an unsupported status
+ */
+ status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ unlock_kernel();
+
+ printk(KERN_WARNING "write status is %d\n", (int)status);
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static int efi_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct efi_rtc *p = dev_get_drvdata(dev);
+ unsigned long flags;
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
+
+ lock_kernel();
+
+ spin_lock_irqsave(&p->lock, flags);
+ status = efi.get_time(&eft, &cap);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ unlock_kernel();
+
+ if (status != EFI_SUCCESS) {
+ /* should never happen */
+ printk(KERN_ERR "efitime: can't read time\n");
+ return -EINVAL;
+ }
+
+ convert_from_efi_time(&eft, tm);
+
+ return 0;
+}
+
+static int efi_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct efi_rtc *p = dev_get_drvdata(dev);
+ unsigned long flags;
+ efi_status_t status;
+ efi_time_t eft;
+
+ convert_to_efi_time(tm, &eft);
+
+ lock_kernel();
+
+ spin_lock_irqsave(&p->lock, flags);
+ status = efi.set_time(&eft);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ unlock_kernel();
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static const struct rtc_class_ops efi_rtc_ops = {
+ .read_time = efi_read_time,
+ .set_time = efi_set_time,
+ .read_alarm = efi_read_alarm,
+ .set_alarm = efi_set_alarm,
+};
+
+static int __devinit efi_rtc_probe(struct platform_device *dev)
+{
+ struct efi_rtc *p;
+
+ p = kzalloc(sizeof (*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ spin_lock_init(&p->lock);
+
+ p->rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(p->rtc)) {
+ int err = PTR_ERR(p->rtc);
+ kfree(p);
+ return err;
+ }
+
+ platform_set_drvdata(dev, p);
+
+ return 0;
+}
+
+static int __devexit efi_rtc_remove(struct platform_device *dev)
+{
+ struct efi_rtc *p = platform_get_drvdata(dev);
+
+ rtc_device_unregister(p->rtc);
+ kfree(p);
+
+ return 0;
+}
+
+static struct platform_driver efi_rtc_driver = {
+ .driver = {
+ .name = "rtc-efi",
+ .owner = THIS_MODULE,
+ },
+ .probe = efi_rtc_probe,
+ .remove = __devexit_p(efi_rtc_remove),
+};
+
+static int __init efi_rtc_init(void)
+{
+ return platform_driver_register(&efi_rtc_driver);
+}
+
+static void __exit efi_rtc_exit(void)
+{
+ platform_driver_unregister(&efi_rtc_driver);
+}
+
+module_init(efi_rtc_init);
+module_exit(efi_rtc_exit);
+
+MODULE_AUTHOR("dann frazier <dannf@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EFI RTC driver");
--
1.5.6.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [rtc-linux] [PATCH] add rtc platform driver for EFI
2009-01-09 0:56 [PATCH] add rtc platform driver for EFI dann frazier
@ 2009-01-09 2:27 ` Alessandro Zummo
2009-01-09 21:34 ` dann frazier
2009-01-09 21:36 ` dann frazier
0 siblings, 2 replies; 16+ messages in thread
From: Alessandro Zummo @ 2009-01-09 2:27 UTC (permalink / raw)
To: rtc-linux; +Cc: dannf, linux-ia64, linux-kernel
On Thu, 8 Jan 2009 17:56:45 -0700
dann frazier <dannf@hp.com> wrote:
a few comments below. please
also check http://groups.google.com/group/rtc-linux/web/checklist
> Munge Stephane Eranian's efirtc.c code into an rtc platform driver
>
> Signed-off-by: dann frazier <dannf@hp.com>
> ---
> arch/ia64/kernel/time.c | 18 +++
> drivers/rtc/Kconfig | 10 ++
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-efi.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 323 insertions(+), 0 deletions(-)
> create mode 100644 drivers/rtc/rtc-efi.c
>
> diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
> index f0ebb34..9ed5ba0 100644
> --- a/arch/ia64/kernel/time.c
> +++ b/arch/ia64/kernel/time.c
> @@ -20,6 +20,7 @@
> #include <linux/efi.h>
> #include <linux/timex.h>
> #include <linux/clocksource.h>
> +#include <linux/platform_device.h>
>
> #include <asm/machvec.h>
> #include <asm/delay.h>
> @@ -405,6 +406,23 @@ static struct irqaction timer_irqaction = {
> .name = "timer"
> };
>
> +struct platform_device rtc_efi_dev = {
> + .name = "rtc-efi",
> + .id = -1,
> +};
> +
> +static int __init rtc_init(void)
> +{
> + int ret;
> + ret = platform_device_register(&rtc_efi_dev);
> + if (ret < 0)
> + printk(KERN_ERR "unable to register rtc device...\n");
> +
> + /* not necessarily an error */
> + return 0;
> +}
> +module_init(rtc_init);
> +
> void __init
> time_init (void)
> {
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 165a818..37ce842 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -433,6 +433,16 @@ config RTC_DRV_DS1742
> This driver can also be built as a module. If so, the module
> will be called rtc-ds1742.
>
> +config RTC_DRV_EFI
> + tristate "EFI RTC"
> + depends on IA64
> + help
> + If you say yes here you will get support for the EFI
> + Real Time Clock.
> +
> + This driver can also be built as a module. If so, the module
> + will be called rtc-efi.
> +
> config RTC_DRV_STK17TA8
> tristate "Simtek STK17TA8"
> depends on RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 6e79c91..29db401 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
> obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
> obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
> obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
> +obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
> obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
> obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
> obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
> diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
> new file mode 100644
> index 0000000..2386da0
> --- /dev/null
> +++ b/drivers/rtc/rtc-efi.c
> @@ -0,0 +1,294 @@
> +/*
> + * rtc-efi: RTC Class Driver for EFI-based systems
> + *
> + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
> + *
> + * Author: dann frazier <dannf@hp.com>
> + * Based on efirtc.c by Stephane Eranian
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/time.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/efi.h>
> +
> +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
> +/*
> + * EFI Epoch is 1/1/1998
> + */
> +#define EFI_RTC_EPOCH 1998
> +
> +#define is_leap(year) \
> + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
> +
> +struct efi_rtc {
> + struct rtc_device *rtc;
> + spinlock_t lock;
> +};
> +
> +static const unsigned short int __mon_yday[2][13] =
> +{
> + /* Normal years. */
> + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
> + /* Leap years. */
> + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
> +};
please check drivers/rtc/rtc-lib.c
> +/*
> + * returns day of the year [0-365]
> + */
> +static inline int
> +compute_yday(efi_time_t *eft)
> +{
> + /* efi_time_t.month is in the [1-12] so, we need -1 */
> + return __mon_yday[is_leap(eft->year)][eft->month-1] + eft->day - 1;
> +}
> +/*
> + * returns day of the week [0-6] 0=Sunday
> + *
> + * Don't try to provide a year that's before 1998, please !
> + */
> +static int
> +compute_wday(efi_time_t *eft)
> +{
> + int y;
> + int ndays = 0;
> +
> + if (eft->year < 1998) {
> + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
> + return -1;
> + }
> +
> + for (y = EFI_RTC_EPOCH; y < eft->year; y++)
> + ndays += 365 + (is_leap(y) ? 1 : 0);
> +
> + ndays += compute_yday(eft);
> +
> + /*
> + * 4=1/1/1998 was a Thursday
> + */
> + return (ndays + 4) % 7;
> +}
> +
> +static void
> +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
> +{
> +
> + eft->year = wtime->tm_year + 1900;
> + eft->month = wtime->tm_mon + 1;
> + eft->day = wtime->tm_mday;
> + eft->hour = wtime->tm_hour;
> + eft->minute = wtime->tm_min;
> + eft->second = wtime->tm_sec;
> + eft->nanosecond = 0;
> + eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
> + eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
> +}
> +
> +static void
> +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
> +{
> + memset(wtime, 0, sizeof(*wtime));
> + wtime->tm_sec = eft->second;
> + wtime->tm_min = eft->minute;
> + wtime->tm_hour = eft->hour;
> + wtime->tm_mday = eft->day;
> + wtime->tm_mon = eft->month - 1;
> + wtime->tm_year = eft->year - 1900;
> +
> + /* day of the week [0-6], Sunday=0 */
> + wtime->tm_wday = compute_wday(eft);
> +
> + /* day in the year [1-365]*/
> + wtime->tm_yday = compute_yday(eft);
> +
> +
> + switch (eft->daylight & EFI_ISDST) {
> + case EFI_ISDST:
> + wtime->tm_isdst = 1;
> + break;
> + case EFI_TIME_ADJUST_DAYLIGHT:
> + wtime->tm_isdst = 0;
> + break;
> + default:
> + wtime->tm_isdst = -1;
> + }
> +}
> +
> +static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> +{
> + struct efi_rtc *p = dev_get_drvdata(dev);
> + efi_time_t eft;
> + efi_status_t status;
> + unsigned long flags;
> +
> + lock_kernel();
> +
> + spin_lock_irqsave(&p->lock, flags);
you don't need your own lock, the rtc subsystem provides
ops locking.
> + /*
> + * As of EFI v1.10, this call always returns an unsupported status
> + */
> + status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
> + (efi_bool_t *)&wkalrm->pending, &eft);
> + spin_unlock_irqrestore(&p->lock, flags);
> +
> + unlock_kernel();
> +
> + if (status != EFI_SUCCESS)
> + return -EINVAL;
> +
> + convert_from_efi_time(&eft, &wkalrm->time);
> +
> + return 0;
use return rtc_valid_tm
> +}
> +
> +static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> +{
> + struct efi_rtc *p = dev_get_drvdata(dev);
> + efi_time_t eft;
> + efi_status_t status;
> + unsigned long flags;
> +
> + convert_to_efi_time(&wkalrm->time, &eft);
> +
> + lock_kernel();
> +
> + spin_lock_irqsave(&p->lock, flags);
> + /*
> + * XXX Fixme:
> + * As of EFI 0.92 with the firmware I have on my
> + * machine this call does not seem to work quite
> + * right
> + *
> + * As of v1.10, this call always returns an unsupported status
> + */
> + status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
> + spin_unlock_irqrestore(&p->lock, flags);
> +
> + unlock_kernel();
> +
> + printk(KERN_WARNING "write status is %d\n", (int)status);
> +
> + return status == EFI_SUCCESS ? 0 : -EINVAL;
> +}
> +
> +static int efi_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct efi_rtc *p = dev_get_drvdata(dev);
> + unsigned long flags;
> + efi_status_t status;
> + efi_time_t eft;
> + efi_time_cap_t cap;
> +
> + lock_kernel();
> +
> + spin_lock_irqsave(&p->lock, flags);
> + status = efi.get_time(&eft, &cap);
> + spin_unlock_irqrestore(&p->lock, flags);
> +
> + unlock_kernel();
> +
> + if (status != EFI_SUCCESS) {
> + /* should never happen */
> + printk(KERN_ERR "efitime: can't read time\n");
> + return -EINVAL;
> + }
> +
> + convert_from_efi_time(&eft, tm);
> +
> + return 0;
use rtc_valid_tm
> +}
> +
> +static int efi_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct efi_rtc *p = dev_get_drvdata(dev);
> + unsigned long flags;
> + efi_status_t status;
> + efi_time_t eft;
> +
> + convert_to_efi_time(tm, &eft);
> +
> + lock_kernel();
> +
> + spin_lock_irqsave(&p->lock, flags);
> + status = efi.set_time(&eft);
> + spin_unlock_irqrestore(&p->lock, flags);
> +
> + unlock_kernel();
> +
> + return status == EFI_SUCCESS ? 0 : -EINVAL;
> +}
> +
> +static const struct rtc_class_ops efi_rtc_ops = {
> + .read_time = efi_read_time,
> + .set_time = efi_set_time,
> + .read_alarm = efi_read_alarm,
> + .set_alarm = efi_set_alarm,
> +};
> +
> +static int __devinit efi_rtc_probe(struct platform_device *dev)
> +{
> + struct efi_rtc *p;
> +
> + p = kzalloc(sizeof (*p), GFP_KERNEL);
> + if (!p)
> + return -ENOMEM;
> +
> + spin_lock_init(&p->lock);
> +
> + p->rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
> + THIS_MODULE);
> + if (IS_ERR(p->rtc)) {
> + int err = PTR_ERR(p->rtc);
> + kfree(p);
> + return err;
> + }
> +
> + platform_set_drvdata(dev, p);
> +
> + return 0;
> +}
> +
> +static int __devexit efi_rtc_remove(struct platform_device *dev)
> +{
> + struct efi_rtc *p = platform_get_drvdata(dev);
> +
> + rtc_device_unregister(p->rtc);
> + kfree(p);
> +
> + return 0;
> +}
> +
> +static struct platform_driver efi_rtc_driver = {
> + .driver = {
> + .name = "rtc-efi",
> + .owner = THIS_MODULE,
> + },
> + .probe = efi_rtc_probe,
> + .remove = __devexit_p(efi_rtc_remove),
> +};
> +
> +static int __init efi_rtc_init(void)
> +{
> + return platform_driver_register(&efi_rtc_driver);
you can probably use platform_driver_probe
> +}
> +
> +static void __exit efi_rtc_exit(void)
> +{
> + platform_driver_unregister(&efi_rtc_driver);
> +}
> +
> +module_init(efi_rtc_init);
> +module_exit(efi_rtc_exit);
> +
> +MODULE_AUTHOR("dann frazier <dannf@hp.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("EFI RTC driver");
> --
> 1.5.6.5
>
>
> --~--~---------~--~----~------------~-------~--~----~
> You received this message because you are subscribed to "rtc-linux".
> Membership options at http://groups.google.com/group/rtc-linux .
> Please read http://groups.google.com/group/rtc-linux/web/checklist
> before submitting a driver.
> -~----------~----~----~----~------~----~------~--~---
>
--
Best regards,
Alessandro Zummo,
Tower Technologies - Torino, Italy
http://www.towertech.it
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rtc-linux] [PATCH] add rtc platform driver for EFI
2009-01-09 2:27 ` [rtc-linux] " Alessandro Zummo
@ 2009-01-09 21:34 ` dann frazier
2009-01-09 21:36 ` dann frazier
1 sibling, 0 replies; 16+ messages in thread
From: dann frazier @ 2009-01-09 21:34 UTC (permalink / raw)
To: Alessandro Zummo; +Cc: rtc-linux, linux-ia64, linux-kernel
On Fri, Jan 09, 2009 at 03:27:29AM +0100, Alessandro Zummo wrote:
> On Thu, 8 Jan 2009 17:56:45 -0700
> dann frazier <dannf@hp.com> wrote:
>
> a few comments below. please
> also check http://groups.google.com/group/rtc-linux/web/checklist
Thanks for the pointer. I _think_ I comply, after fixing the
individual issues you brought up below.
One question is with:
"do not kfree() what's returned by rtc_device_register()"
I do kfree the return if it comes back as an error - is that still
correct?
> > Munge Stephane Eranian's efirtc.c code into an rtc platform driver
> >
> > Signed-off-by: dann frazier <dannf@hp.com>
> > ---
> > arch/ia64/kernel/time.c | 18 +++
> > drivers/rtc/Kconfig | 10 ++
> > drivers/rtc/Makefile | 1 +
> > drivers/rtc/rtc-efi.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 323 insertions(+), 0 deletions(-)
> > create mode 100644 drivers/rtc/rtc-efi.c
> >
> > diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
> > index f0ebb34..9ed5ba0 100644
> > --- a/arch/ia64/kernel/time.c
> > +++ b/arch/ia64/kernel/time.c
> > @@ -20,6 +20,7 @@
> > #include <linux/efi.h>
> > #include <linux/timex.h>
> > #include <linux/clocksource.h>
> > +#include <linux/platform_device.h>
> >
> > #include <asm/machvec.h>
> > #include <asm/delay.h>
> > @@ -405,6 +406,23 @@ static struct irqaction timer_irqaction = {
> > .name = "timer"
> > };
> >
> > +struct platform_device rtc_efi_dev = {
> > + .name = "rtc-efi",
> > + .id = -1,
> > +};
> > +
> > +static int __init rtc_init(void)
> > +{
> > + int ret;
> > + ret = platform_device_register(&rtc_efi_dev);
> > + if (ret < 0)
> > + printk(KERN_ERR "unable to register rtc device...\n");
> > +
> > + /* not necessarily an error */
> > + return 0;
> > +}
> > +module_init(rtc_init);
> > +
> > void __init
> > time_init (void)
> > {
> > diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> > index 165a818..37ce842 100644
> > --- a/drivers/rtc/Kconfig
> > +++ b/drivers/rtc/Kconfig
> > @@ -433,6 +433,16 @@ config RTC_DRV_DS1742
> > This driver can also be built as a module. If so, the module
> > will be called rtc-ds1742.
> >
> > +config RTC_DRV_EFI
> > + tristate "EFI RTC"
> > + depends on IA64
> > + help
> > + If you say yes here you will get support for the EFI
> > + Real Time Clock.
> > +
> > + This driver can also be built as a module. If so, the module
> > + will be called rtc-efi.
> > +
> > config RTC_DRV_STK17TA8
> > tristate "Simtek STK17TA8"
> > depends on RTC_CLASS
> > diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> > index 6e79c91..29db401 100644
> > --- a/drivers/rtc/Makefile
> > +++ b/drivers/rtc/Makefile
> > @@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
> > obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
> > obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
> > obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
> > +obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
> > obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
> > obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
> > obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
> > diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
> > new file mode 100644
> > index 0000000..2386da0
> > --- /dev/null
> > +++ b/drivers/rtc/rtc-efi.c
> > @@ -0,0 +1,294 @@
> > +/*
> > + * rtc-efi: RTC Class Driver for EFI-based systems
> > + *
> > + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
> > + *
> > + * Author: dann frazier <dannf@hp.com>
> > + * Based on efirtc.c by Stephane Eranian
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms of the GNU General Public License as published by the
> > + * Free Software Foundation; either version 2 of the License, or (at your
> > + * option) any later version.
> > + *
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/time.h>
> > +#include <linux/platform_device.h>
> > +
> > +#include <linux/efi.h>
> > +
> > +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
> > +/*
> > + * EFI Epoch is 1/1/1998
> > + */
> > +#define EFI_RTC_EPOCH 1998
> > +
> > +#define is_leap(year) \
> > + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
> > +
> > +struct efi_rtc {
> > + struct rtc_device *rtc;
> > + spinlock_t lock;
> > +};
> > +
> > +static const unsigned short int __mon_yday[2][13] =
> > +{
> > + /* Normal years. */
> > + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
> > + /* Leap years. */
> > + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
> > +};
>
> please check drivers/rtc/rtc-lib.c
ah nice, fixed.
> > +/*
> > + * returns day of the year [0-365]
> > + */
> > +static inline int
> > +compute_yday(efi_time_t *eft)
> > +{
> > + /* efi_time_t.month is in the [1-12] so, we need -1 */
> > + return __mon_yday[is_leap(eft->year)][eft->month-1] + eft->day - 1;
> > +}
> > +/*
> > + * returns day of the week [0-6] 0=Sunday
> > + *
> > + * Don't try to provide a year that's before 1998, please !
> > + */
> > +static int
> > +compute_wday(efi_time_t *eft)
> > +{
> > + int y;
> > + int ndays = 0;
> > +
> > + if (eft->year < 1998) {
> > + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
> > + return -1;
> > + }
> > +
> > + for (y = EFI_RTC_EPOCH; y < eft->year; y++)
> > + ndays += 365 + (is_leap(y) ? 1 : 0);
> > +
> > + ndays += compute_yday(eft);
> > +
> > + /*
> > + * 4=1/1/1998 was a Thursday
> > + */
> > + return (ndays + 4) % 7;
> > +}
> > +
> > +static void
> > +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
> > +{
> > +
> > + eft->year = wtime->tm_year + 1900;
> > + eft->month = wtime->tm_mon + 1;
> > + eft->day = wtime->tm_mday;
> > + eft->hour = wtime->tm_hour;
> > + eft->minute = wtime->tm_min;
> > + eft->second = wtime->tm_sec;
> > + eft->nanosecond = 0;
> > + eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
> > + eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
> > +}
> > +
> > +static void
> > +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
> > +{
> > + memset(wtime, 0, sizeof(*wtime));
> > + wtime->tm_sec = eft->second;
> > + wtime->tm_min = eft->minute;
> > + wtime->tm_hour = eft->hour;
> > + wtime->tm_mday = eft->day;
> > + wtime->tm_mon = eft->month - 1;
> > + wtime->tm_year = eft->year - 1900;
> > +
> > + /* day of the week [0-6], Sunday=0 */
> > + wtime->tm_wday = compute_wday(eft);
> > +
> > + /* day in the year [1-365]*/
> > + wtime->tm_yday = compute_yday(eft);
> > +
> > +
> > + switch (eft->daylight & EFI_ISDST) {
> > + case EFI_ISDST:
> > + wtime->tm_isdst = 1;
> > + break;
> > + case EFI_TIME_ADJUST_DAYLIGHT:
> > + wtime->tm_isdst = 0;
> > + break;
> > + default:
> > + wtime->tm_isdst = -1;
> > + }
> > +}
> > +
> > +static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> > +{
> > + struct efi_rtc *p = dev_get_drvdata(dev);
> > + efi_time_t eft;
> > + efi_status_t status;
> > + unsigned long flags;
> > +
> > + lock_kernel();
> > +
> > + spin_lock_irqsave(&p->lock, flags);
>
> you don't need your own lock, the rtc subsystem provides
> ops locking.
cool, removed.
> > + /*
> > + * As of EFI v1.10, this call always returns an unsupported status
> > + */
> > + status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
> > + (efi_bool_t *)&wkalrm->pending, &eft);
> > + spin_unlock_irqrestore(&p->lock, flags);
> > +
> > + unlock_kernel();
> > +
> > + if (status != EFI_SUCCESS)
> > + return -EINVAL;
> > +
> > + convert_from_efi_time(&eft, &wkalrm->time);
> > +
> > + return 0;
>
> use return rtc_valid_tm
fixed
> > +}
> > +
> > +static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> > +{
> > + struct efi_rtc *p = dev_get_drvdata(dev);
> > + efi_time_t eft;
> > + efi_status_t status;
> > + unsigned long flags;
> > +
> > + convert_to_efi_time(&wkalrm->time, &eft);
> > +
> > + lock_kernel();
> > +
> > + spin_lock_irqsave(&p->lock, flags);
> > + /*
> > + * XXX Fixme:
> > + * As of EFI 0.92 with the firmware I have on my
> > + * machine this call does not seem to work quite
> > + * right
> > + *
> > + * As of v1.10, this call always returns an unsupported status
> > + */
> > + status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
> > + spin_unlock_irqrestore(&p->lock, flags);
> > +
> > + unlock_kernel();
> > +
> > + printk(KERN_WARNING "write status is %d\n", (int)status);
> > +
> > + return status == EFI_SUCCESS ? 0 : -EINVAL;
> > +}
> > +
> > +static int efi_read_time(struct device *dev, struct rtc_time *tm)
> > +{
> > + struct efi_rtc *p = dev_get_drvdata(dev);
> > + unsigned long flags;
> > + efi_status_t status;
> > + efi_time_t eft;
> > + efi_time_cap_t cap;
> > +
> > + lock_kernel();
> > +
> > + spin_lock_irqsave(&p->lock, flags);
> > + status = efi.get_time(&eft, &cap);
> > + spin_unlock_irqrestore(&p->lock, flags);
> > +
> > + unlock_kernel();
> > +
> > + if (status != EFI_SUCCESS) {
> > + /* should never happen */
> > + printk(KERN_ERR "efitime: can't read time\n");
> > + return -EINVAL;
> > + }
> > +
> > + convert_from_efi_time(&eft, tm);
> > +
> > + return 0;
>
> use rtc_valid_tm
fixed
> > +}
> > +
> > +static int efi_set_time(struct device *dev, struct rtc_time *tm)
> > +{
> > + struct efi_rtc *p = dev_get_drvdata(dev);
> > + unsigned long flags;
> > + efi_status_t status;
> > + efi_time_t eft;
> > +
> > + convert_to_efi_time(tm, &eft);
> > +
> > + lock_kernel();
> > +
> > + spin_lock_irqsave(&p->lock, flags);
> > + status = efi.set_time(&eft);
> > + spin_unlock_irqrestore(&p->lock, flags);
> > +
> > + unlock_kernel();
> > +
> > + return status == EFI_SUCCESS ? 0 : -EINVAL;
> > +}
> > +
> > +static const struct rtc_class_ops efi_rtc_ops = {
> > + .read_time = efi_read_time,
> > + .set_time = efi_set_time,
> > + .read_alarm = efi_read_alarm,
> > + .set_alarm = efi_set_alarm,
> > +};
> > +
> > +static int __devinit efi_rtc_probe(struct platform_device *dev)
> > +{
> > + struct efi_rtc *p;
> > +
> > + p = kzalloc(sizeof (*p), GFP_KERNEL);
> > + if (!p)
> > + return -ENOMEM;
> > +
> > + spin_lock_init(&p->lock);
> > +
> > + p->rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
> > + THIS_MODULE);
> > + if (IS_ERR(p->rtc)) {
> > + int err = PTR_ERR(p->rtc);
> > + kfree(p);
> > + return err;
> > + }
> > +
> > + platform_set_drvdata(dev, p);
> > +
> > + return 0;
> > +}
> > +
> > +static int __devexit efi_rtc_remove(struct platform_device *dev)
> > +{
> > + struct efi_rtc *p = platform_get_drvdata(dev);
> > +
> > + rtc_device_unregister(p->rtc);
> > + kfree(p);
> > +
> > + return 0;
> > +}
> > +
> > +static struct platform_driver efi_rtc_driver = {
> > + .driver = {
> > + .name = "rtc-efi",
> > + .owner = THIS_MODULE,
> > + },
> > + .probe = efi_rtc_probe,
> > + .remove = __devexit_p(efi_rtc_remove),
> > +};
> > +
> > +static int __init efi_rtc_init(void)
> > +{
> > + return platform_driver_register(&efi_rtc_driver);
>
> you can probably use platform_driver_probe
done
> > +}
> > +
> > +static void __exit efi_rtc_exit(void)
> > +{
> > + platform_driver_unregister(&efi_rtc_driver);
> > +}
> > +
> > +module_init(efi_rtc_init);
> > +module_exit(efi_rtc_exit);
> > +
> > +MODULE_AUTHOR("dann frazier <dannf@hp.com>");
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("EFI RTC driver");
Will follow up w/ new patch.
--
dann frazier
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH] add rtc platform driver for EFI
2009-01-09 2:27 ` [rtc-linux] " Alessandro Zummo
2009-01-09 21:34 ` dann frazier
@ 2009-01-09 21:36 ` dann frazier
2009-01-13 8:39 ` Andrew Morton
1 sibling, 1 reply; 16+ messages in thread
From: dann frazier @ 2009-01-09 21:36 UTC (permalink / raw)
To: Alessandro Zummo; +Cc: rtc-linux, linux-ia64, linux-kernel
Munge Stephane Eranian's efirtc.c code into an rtc platform driver
Signed-off-by: dann frazier <dannf@hp.com>
---
arch/ia64/kernel/time.c | 18 +++
drivers/rtc/Kconfig | 10 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-efi.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 304 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-efi.c
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index f0ebb34..9ed5ba0 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -20,6 +20,7 @@
#include <linux/efi.h>
#include <linux/timex.h>
#include <linux/clocksource.h>
+#include <linux/platform_device.h>
#include <asm/machvec.h>
#include <asm/delay.h>
@@ -405,6 +406,23 @@ static struct irqaction timer_irqaction = {
.name = "timer"
};
+struct platform_device rtc_efi_dev = {
+ .name = "rtc-efi",
+ .id = -1,
+};
+
+static int __init rtc_init(void)
+{
+ int ret;
+ ret = platform_device_register(&rtc_efi_dev);
+ if (ret < 0)
+ printk(KERN_ERR "unable to register rtc device...\n");
+
+ /* not necessarily an error */
+ return 0;
+}
+module_init(rtc_init);
+
void __init
time_init (void)
{
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 4ad831d..2cc8a9d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -434,6 +434,16 @@ config RTC_DRV_DS1742
This driver can also be built as a module. If so, the module
will be called rtc-ds1742.
+config RTC_DRV_EFI
+ tristate "EFI RTC"
+ depends on IA64
+ help
+ If you say yes here you will get support for the EFI
+ Real Time Clock.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-efi.
+
config RTC_DRV_STK17TA8
tristate "Simtek STK17TA8"
depends on RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 9a4340d..09ae207 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
+obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
new file mode 100644
index 0000000..1e9607b
--- /dev/null
+++ b/drivers/rtc/rtc-efi.c
@@ -0,0 +1,275 @@
+/*
+ * rtc-efi: RTC Class Driver for EFI-based systems
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Author: dann frazier <dannf@hp.com>
+ * Based on efirtc.c by Stephane Eranian
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+
+#include <linux/efi.h>
+
+#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
+/*
+ * EFI Epoch is 1/1/1998
+ */
+#define EFI_RTC_EPOCH 1998
+
+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+
+struct efi_rtc {
+ struct rtc_device *rtc;
+ spinlock_t lock;
+};
+
+static const unsigned short int __mon_yday[2][13] =
+{
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
+/*
+ * returns day of the year [0-365]
+ */
+static inline int
+compute_yday(efi_time_t *eft)
+{
+ /* efi_time_t.month is in the [1-12] so, we need -1 */
+ return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
+}
+/*
+ * returns day of the week [0-6] 0=Sunday
+ *
+ * Don't try to provide a year that's before 1998, please !
+ */
+static int
+compute_wday(efi_time_t *eft)
+{
+ int y;
+ int ndays = 0;
+
+ if (eft->year < 1998) {
+ printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+ return -1;
+ }
+
+ for (y = EFI_RTC_EPOCH; y < eft->year; y++)
+ ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
+
+ ndays += compute_yday(eft);
+
+ /*
+ * 4=1/1/1998 was a Thursday
+ */
+ return (ndays + 4) % 7;
+}
+
+static void
+convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
+{
+
+ eft->year = wtime->tm_year + 1900;
+ eft->month = wtime->tm_mon + 1;
+ eft->day = wtime->tm_mday;
+ eft->hour = wtime->tm_hour;
+ eft->minute = wtime->tm_min;
+ eft->second = wtime->tm_sec;
+ eft->nanosecond = 0;
+ eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
+ eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
+}
+
+static void
+convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
+{
+ memset(wtime, 0, sizeof(*wtime));
+ wtime->tm_sec = eft->second;
+ wtime->tm_min = eft->minute;
+ wtime->tm_hour = eft->hour;
+ wtime->tm_mday = eft->day;
+ wtime->tm_mon = eft->month - 1;
+ wtime->tm_year = eft->year - 1900;
+
+ /* day of the week [0-6], Sunday=0 */
+ wtime->tm_wday = compute_wday(eft);
+
+ /* day in the year [1-365]*/
+ wtime->tm_yday = compute_yday(eft);
+
+
+ switch (eft->daylight & EFI_ISDST) {
+ case EFI_ISDST:
+ wtime->tm_isdst = 1;
+ break;
+ case EFI_TIME_ADJUST_DAYLIGHT:
+ wtime->tm_isdst = 0;
+ break;
+ default:
+ wtime->tm_isdst = -1;
+ }
+}
+
+static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ efi_time_t eft;
+ efi_status_t status;
+
+ lock_kernel();
+
+ /*
+ * As of EFI v1.10, this call always returns an unsupported status
+ */
+ status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
+ (efi_bool_t *)&wkalrm->pending, &eft);
+
+ unlock_kernel();
+
+ if (status != EFI_SUCCESS)
+ return -EINVAL;
+
+ convert_from_efi_time(&eft, &wkalrm->time);
+
+ return rtc_valid_tm(&wkalrm->time);
+}
+
+static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ efi_time_t eft;
+ efi_status_t status;
+
+ convert_to_efi_time(&wkalrm->time, &eft);
+
+ lock_kernel();
+
+ /*
+ * XXX Fixme:
+ * As of EFI 0.92 with the firmware I have on my
+ * machine this call does not seem to work quite
+ * right
+ *
+ * As of v1.10, this call always returns an unsupported status
+ */
+ status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
+
+ unlock_kernel();
+
+ printk(KERN_WARNING "write status is %d\n", (int)status);
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static int efi_read_time(struct device *dev, struct rtc_time *tm)
+{
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
+
+ lock_kernel();
+
+ status = efi.get_time(&eft, &cap);
+
+ unlock_kernel();
+
+ if (status != EFI_SUCCESS) {
+ /* should never happen */
+ printk(KERN_ERR "efitime: can't read time\n");
+ return -EINVAL;
+ }
+
+ convert_from_efi_time(&eft, tm);
+
+ return rtc_valid_tm(tm);
+}
+
+static int efi_set_time(struct device *dev, struct rtc_time *tm)
+{
+ efi_status_t status;
+ efi_time_t eft;
+
+ convert_to_efi_time(tm, &eft);
+
+ lock_kernel();
+
+ status = efi.set_time(&eft);
+
+ unlock_kernel();
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static const struct rtc_class_ops efi_rtc_ops = {
+ .read_time = efi_read_time,
+ .set_time = efi_set_time,
+ .read_alarm = efi_read_alarm,
+ .set_alarm = efi_set_alarm,
+};
+
+static int __devinit efi_rtc_probe(struct platform_device *dev)
+{
+ struct rtc_device *rtc;
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ int err = PTR_ERR(rtc);
+ kfree(rtc);
+ return err;
+ }
+
+ platform_set_drvdata(dev, rtc);
+
+ return 0;
+}
+
+static int __devexit efi_rtc_remove(struct platform_device *dev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ rtc_device_unregister(rtc);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct platform_driver efi_rtc_driver = {
+ .driver = {
+ .name = "rtc-efi",
+ .owner = THIS_MODULE,
+ },
+ .probe = efi_rtc_probe,
+ .remove = __devexit_p(efi_rtc_remove),
+};
+
+static int __init efi_rtc_init(void)
+{
+ return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
+}
+
+static void __exit efi_rtc_exit(void)
+{
+ platform_driver_unregister(&efi_rtc_driver);
+}
+
+module_init(efi_rtc_init);
+module_exit(efi_rtc_exit);
+
+MODULE_AUTHOR("dann frazier <dannf@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EFI RTC driver");
--
1.5.3.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] add rtc platform driver for EFI
2009-01-09 21:36 ` dann frazier
@ 2009-01-13 8:39 ` Andrew Morton
2009-01-14 0:00 ` dann frazier
0 siblings, 1 reply; 16+ messages in thread
From: Andrew Morton @ 2009-01-13 8:39 UTC (permalink / raw)
To: dann frazier
Cc: Alessandro Zummo, rtc-linux, linux-ia64, linux-kernel,
stephane eranian
On Fri, 9 Jan 2009 14:36:16 -0700 dann frazier <dannf@dannf.org> wrote:
> Munge Stephane Eranian's efirtc.c code into an rtc platform driver
>
>
> ...
>
> index f0ebb34..9ed5ba0 100644
> --- a/arch/ia64/kernel/time.c
> +++ b/arch/ia64/kernel/time.c
> @@ -20,6 +20,7 @@
> #include <linux/efi.h>
> #include <linux/timex.h>
> #include <linux/clocksource.h>
> +#include <linux/platform_device.h>
>
> #include <asm/machvec.h>
> #include <asm/delay.h>
> @@ -405,6 +406,23 @@ static struct irqaction timer_irqaction = {
> .name = "timer"
> };
>
> +struct platform_device rtc_efi_dev = {
static, please.
> + .name = "rtc-efi",
> + .id = -1,
> +};
> +
> +static int __init rtc_init(void)
> +{
> + int ret;
> + ret = platform_device_register(&rtc_efi_dev);
> + if (ret < 0)
> + printk(KERN_ERR "unable to register rtc device...\n");
we don't really need `ret'...
> + /* not necessarily an error */
> + return 0;
> +}
> +module_init(rtc_init);
> +
> void __init
> time_init (void)
> {
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 4ad831d..2cc8a9d 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -434,6 +434,16 @@ config RTC_DRV_DS1742
> This driver can also be built as a module. If so, the module
> will be called rtc-ds1742.
>
> +config RTC_DRV_EFI
> + tristate "EFI RTC"
> + depends on IA64
> + help
> + If you say yes here you will get support for the EFI
> + Real Time Clock.
> +
> + This driver can also be built as a module. If so, the module
> + will be called rtc-efi.
> +
> config RTC_DRV_STK17TA8
> tristate "Simtek STK17TA8"
> depends on RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 9a4340d..09ae207 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
> obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
> obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
> obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
> +obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
> obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
> obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
> obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
> diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
> new file mode 100644
> index 0000000..1e9607b
> --- /dev/null
> +++ b/drivers/rtc/rtc-efi.c
> @@ -0,0 +1,275 @@
> +/*
> + * rtc-efi: RTC Class Driver for EFI-based systems
> + *
> + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
> + *
> + * Author: dann frazier <dannf@hp.com>
> + * Based on efirtc.c by Stephane Eranian
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/time.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/efi.h>
> +
> +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
> +/*
> + * EFI Epoch is 1/1/1998
> + */
> +#define EFI_RTC_EPOCH 1998
> +
> +#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
> +
> +struct efi_rtc {
> + struct rtc_device *rtc;
> + spinlock_t lock;
> +};
This never gets used?
> +static const unsigned short int __mon_yday[2][13] =
> +{
static const unsigned short __mon_yday[2][13] = {
please.
> + /* Normal years. */
> + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
> + /* Leap years. */
> + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
> +};
hm, I bet there are other places in the kernel where we use (or need)
that table.
> +
> +/*
> + * returns day of the year [0-365]
> + */
> +static inline int
> +compute_yday(efi_time_t *eft)
> +{
> + /* efi_time_t.month is in the [1-12] so, we need -1 */
> + return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
> +}
> +/*
> + * returns day of the week [0-6] 0=Sunday
> + *
> + * Don't try to provide a year that's before 1998, please !
> + */
> +static int
> +compute_wday(efi_time_t *eft)
> +{
> + int y;
> + int ndays = 0;
> +
> + if (eft->year < 1998) {
> + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
> + return -1;
> + }
> +
> + for (y = EFI_RTC_EPOCH; y < eft->year; y++)
> + ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
> +
> + ndays += compute_yday(eft);
> +
> + /*
> + * 4=1/1/1998 was a Thursday
> + */
> + return (ndays + 4) % 7;
> +}
> +
> +static void
> +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
> +{
> +
dd
> + eft->year = wtime->tm_year + 1900;
> + eft->month = wtime->tm_mon + 1;
> + eft->day = wtime->tm_mday;
> + eft->hour = wtime->tm_hour;
> + eft->minute = wtime->tm_min;
> + eft->second = wtime->tm_sec;
> + eft->nanosecond = 0;
> + eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
> + eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
> +}
> +
> +static void
> +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
> +{
> + memset(wtime, 0, sizeof(*wtime));
> + wtime->tm_sec = eft->second;
> + wtime->tm_min = eft->minute;
> + wtime->tm_hour = eft->hour;
> + wtime->tm_mday = eft->day;
> + wtime->tm_mon = eft->month - 1;
> + wtime->tm_year = eft->year - 1900;
> +
> + /* day of the week [0-6], Sunday=0 */
> + wtime->tm_wday = compute_wday(eft);
> +
> + /* day in the year [1-365]*/
> + wtime->tm_yday = compute_yday(eft);
> +
> +
> + switch (eft->daylight & EFI_ISDST) {
> + case EFI_ISDST:
> + wtime->tm_isdst = 1;
> + break;
> + case EFI_TIME_ADJUST_DAYLIGHT:
> + wtime->tm_isdst = 0;
> + break;
> + default:
> + wtime->tm_isdst = -1;
> + }
> +}
> +
> +static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> +{
> + efi_time_t eft;
> + efi_status_t status;
> +
> + lock_kernel();
> +
> + /*
> + * As of EFI v1.10, this call always returns an unsupported status
> + */
> + status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
> + (efi_bool_t *)&wkalrm->pending, &eft);
> +
> + unlock_kernel();
eek. The patch adds a great pile of lock_kernel() calls. Everyone
else is busily deleting them.
Can we not do this?
> + if (status != EFI_SUCCESS)
> + return -EINVAL;
> +
> + convert_from_efi_time(&eft, &wkalrm->time);
> +
> + return rtc_valid_tm(&wkalrm->time);
> +}
> +
>
> ...
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] add rtc platform driver for EFI
2009-01-13 8:39 ` Andrew Morton
@ 2009-01-14 0:00 ` dann frazier
2009-01-14 1:17 ` dann frazier
0 siblings, 1 reply; 16+ messages in thread
From: dann frazier @ 2009-01-14 0:00 UTC (permalink / raw)
To: Andrew Morton
Cc: Alessandro Zummo, rtc-linux, linux-ia64, linux-kernel,
stephane eranian
On Tue, Jan 13, 2009 at 12:39:34AM -0800, Andrew Morton wrote:
> On Fri, 9 Jan 2009 14:36:16 -0700 dann frazier <dannf@dannf.org> wrote:
>
> > Munge Stephane Eranian's efirtc.c code into an rtc platform driver
> >
> >
> > ...
> >
> > index f0ebb34..9ed5ba0 100644
> > --- a/arch/ia64/kernel/time.c
> > +++ b/arch/ia64/kernel/time.c
> > @@ -20,6 +20,7 @@
> > #include <linux/efi.h>
> > #include <linux/timex.h>
> > #include <linux/clocksource.h>
> > +#include <linux/platform_device.h>
> >
> > #include <asm/machvec.h>
> > #include <asm/delay.h>
> > @@ -405,6 +406,23 @@ static struct irqaction timer_irqaction = {
> > .name = "timer"
> > };
> >
> > +struct platform_device rtc_efi_dev = {
>
> static, please.
fixed
> > + .name = "rtc-efi",
> > + .id = -1,
> > +};
> > +
> > +static int __init rtc_init(void)
> > +{
> > + int ret;
> > + ret = platform_device_register(&rtc_efi_dev);
> > + if (ret < 0)
> > + printk(KERN_ERR "unable to register rtc device...\n");
>
> we don't really need `ret'...
removed
> > + /* not necessarily an error */
> > + return 0;
> > +}
> > +module_init(rtc_init);
> > +
> > void __init
> > time_init (void)
> > {
> > diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> > index 4ad831d..2cc8a9d 100644
> > --- a/drivers/rtc/Kconfig
> > +++ b/drivers/rtc/Kconfig
> > @@ -434,6 +434,16 @@ config RTC_DRV_DS1742
> > This driver can also be built as a module. If so, the module
> > will be called rtc-ds1742.
> >
> > +config RTC_DRV_EFI
> > + tristate "EFI RTC"
> > + depends on IA64
> > + help
> > + If you say yes here you will get support for the EFI
> > + Real Time Clock.
> > +
> > + This driver can also be built as a module. If so, the module
> > + will be called rtc-efi.
> > +
> > config RTC_DRV_STK17TA8
> > tristate "Simtek STK17TA8"
> > depends on RTC_CLASS
> > diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> > index 9a4340d..09ae207 100644
> > --- a/drivers/rtc/Makefile
> > +++ b/drivers/rtc/Makefile
> > @@ -35,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
> > obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
> > obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
> > obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
> > +obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
> > obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
> > obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
> > obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
> > diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
> > new file mode 100644
> > index 0000000..1e9607b
> > --- /dev/null
> > +++ b/drivers/rtc/rtc-efi.c
> > @@ -0,0 +1,275 @@
> > +/*
> > + * rtc-efi: RTC Class Driver for EFI-based systems
> > + *
> > + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
> > + *
> > + * Author: dann frazier <dannf@hp.com>
> > + * Based on efirtc.c by Stephane Eranian
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms of the GNU General Public License as published by the
> > + * Free Software Foundation; either version 2 of the License, or (at your
> > + * option) any later version.
> > + *
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/time.h>
> > +#include <linux/platform_device.h>
> > +
> > +#include <linux/efi.h>
> > +
> > +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
> > +/*
> > + * EFI Epoch is 1/1/1998
> > + */
> > +#define EFI_RTC_EPOCH 1998
> > +
> > +#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
> > +
> > +struct efi_rtc {
> > + struct rtc_device *rtc;
> > + spinlock_t lock;
> > +};
>
> This never gets used?
oops - yeah, removed its usage based on Alessandro's feedback but
forgot to remove the def. removed now.
> > +static const unsigned short int __mon_yday[2][13] =
> > +{
>
> static const unsigned short __mon_yday[2][13] = {
>
> please.
>
> > + /* Normal years. */
> > + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
> > + /* Leap years. */
> > + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
> > +};
>
> hm, I bet there are other places in the kernel where we use (or need)
> that table.
yes, i'm using the one in rtclib now, but forgot to remove the local
def
> > +
> > +/*
> > + * returns day of the year [0-365]
> > + */
> > +static inline int
> > +compute_yday(efi_time_t *eft)
> > +{
> > + /* efi_time_t.month is in the [1-12] so, we need -1 */
> > + return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
> > +}
> > +/*
> > + * returns day of the week [0-6] 0=Sunday
> > + *
> > + * Don't try to provide a year that's before 1998, please !
> > + */
> > +static int
> > +compute_wday(efi_time_t *eft)
> > +{
> > + int y;
> > + int ndays = 0;
> > +
> > + if (eft->year < 1998) {
> > + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
> > + return -1;
> > + }
> > +
> > + for (y = EFI_RTC_EPOCH; y < eft->year; y++)
> > + ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
> > +
> > + ndays += compute_yday(eft);
> > +
> > + /*
> > + * 4=1/1/1998 was a Thursday
> > + */
> > + return (ndays + 4) % 7;
> > +}
> > +
> > +static void
> > +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
> > +{
> > +
>
> dd
just had a vi person explain to me what that means :) done.
> > + eft->year = wtime->tm_year + 1900;
> > + eft->month = wtime->tm_mon + 1;
> > + eft->day = wtime->tm_mday;
> > + eft->hour = wtime->tm_hour;
> > + eft->minute = wtime->tm_min;
> > + eft->second = wtime->tm_sec;
> > + eft->nanosecond = 0;
> > + eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
> > + eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
> > +}
> > +
> > +static void
> > +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
> > +{
> > + memset(wtime, 0, sizeof(*wtime));
> > + wtime->tm_sec = eft->second;
> > + wtime->tm_min = eft->minute;
> > + wtime->tm_hour = eft->hour;
> > + wtime->tm_mday = eft->day;
> > + wtime->tm_mon = eft->month - 1;
> > + wtime->tm_year = eft->year - 1900;
> > +
> > + /* day of the week [0-6], Sunday=0 */
> > + wtime->tm_wday = compute_wday(eft);
> > +
> > + /* day in the year [1-365]*/
> > + wtime->tm_yday = compute_yday(eft);
> > +
> > +
> > + switch (eft->daylight & EFI_ISDST) {
> > + case EFI_ISDST:
> > + wtime->tm_isdst = 1;
> > + break;
> > + case EFI_TIME_ADJUST_DAYLIGHT:
> > + wtime->tm_isdst = 0;
> > + break;
> > + default:
> > + wtime->tm_isdst = -1;
> > + }
> > +}
> > +
> > +static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> > +{
> > + efi_time_t eft;
> > + efi_status_t status;
> > +
> > + lock_kernel();
> > +
> > + /*
> > + * As of EFI v1.10, this call always returns an unsupported status
> > + */
> > + status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
> > + (efi_bool_t *)&wkalrm->pending, &eft);
> > +
> > + unlock_kernel();
>
> eek. The patch adds a great pile of lock_kernel() calls. Everyone
> else is busily deleting them.
>
> Can we not do this?
I copied their usage from the efirtc driver, into which it was
recently pushed down with a request for an EFI expert to clear them
out as necessary. I'm not an EFI expert, but I took a look at the
spec, and section 7.1 of the UEFI spec does say that certain EFI
runtime call sets are not reentrant. I would expect to see that
locking handled internally in the efi layer, but I'm not seeing it.
Since the RTC layer is serializing these calls for us, and we appear
to be the only callers of these functions[1], it looks like it would
be safe to drop the BKL and not introduce other locking. Though, it
may make sense to add locking internally to each of the efi runtime
calls to comform to the spec, just in case this changes.
> > + if (status != EFI_SUCCESS)
> > + return -EINVAL;
> > +
> > + convert_from_efi_time(&eft, &wkalrm->time);
> > +
> > + return rtc_valid_tm(&wkalrm->time);
> > +}
> > +
> >
> > ...
> >
>
[1] efirtc calls them too, of course, but it is Kconfig'd off when
RTC_CLASS is on
--
dann frazier
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH] add rtc platform driver for EFI
2009-01-14 0:00 ` dann frazier
@ 2009-01-14 1:17 ` dann frazier
2009-01-14 1:30 ` [rtc-linux] " Alessandro Zummo
0 siblings, 1 reply; 16+ messages in thread
From: dann frazier @ 2009-01-14 1:17 UTC (permalink / raw)
To: Andrew Morton
Cc: Alessandro Zummo, rtc-linux, linux-ia64, linux-kernel,
stephane eranian
Munge Stephane Eranian's efirtc.c code into an rtc platform driver
Signed-off-by: dann frazier <dannf@hp.com>
---
arch/ia64/kernel/time.c | 16 +++
drivers/rtc/Kconfig | 10 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-efi.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 272 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-efi.c
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index f0ebb34..558051c 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -20,6 +20,7 @@
#include <linux/efi.h>
#include <linux/timex.h>
#include <linux/clocksource.h>
+#include <linux/platform_device.h>
#include <asm/machvec.h>
#include <asm/delay.h>
@@ -405,6 +406,21 @@ static struct irqaction timer_irqaction = {
.name = "timer"
};
+static struct platform_device rtc_efi_dev = {
+ .name = "rtc-efi",
+ .id = -1,
+};
+
+static int __init rtc_init(void)
+{
+ if (platform_device_register(&rtc_efi_dev) < 0)
+ printk(KERN_ERR "unable to register rtc device...\n");
+
+ /* not necessarily an error */
+ return 0;
+}
+module_init(rtc_init);
+
void __init
time_init (void)
{
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cced4d1..56cc98f 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -434,6 +434,16 @@ config RTC_DRV_DS1742
This driver can also be built as a module. If so, the module
will be called rtc-ds1742.
+config RTC_DRV_EFI
+ tristate "EFI RTC"
+ depends on IA64
+ help
+ If you say yes here you will get support for the EFI
+ Real Time Clock.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-efi.
+
config RTC_DRV_STK17TA8
tristate "Simtek STK17TA8"
depends on RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6e28021..7256ce8 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
+obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
new file mode 100644
index 0000000..ddf0459
--- /dev/null
+++ b/drivers/rtc/rtc-efi.c
@@ -0,0 +1,245 @@
+/*
+ * rtc-efi: RTC Class Driver for EFI-based systems
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Author: dann frazier <dannf@hp.com>
+ * Based on efirtc.c by Stephane Eranian
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+
+#include <linux/efi.h>
+
+#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
+/*
+ * EFI Epoch is 1/1/1998
+ */
+#define EFI_RTC_EPOCH 1998
+
+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+
+/*
+ * returns day of the year [0-365]
+ */
+static inline int
+compute_yday(efi_time_t *eft)
+{
+ /* efi_time_t.month is in the [1-12] so, we need -1 */
+ return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
+}
+/*
+ * returns day of the week [0-6] 0=Sunday
+ *
+ * Don't try to provide a year that's before 1998, please !
+ */
+static int
+compute_wday(efi_time_t *eft)
+{
+ int y;
+ int ndays = 0;
+
+ if (eft->year < 1998) {
+ printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+ return -1;
+ }
+
+ for (y = EFI_RTC_EPOCH; y < eft->year; y++)
+ ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
+
+ ndays += compute_yday(eft);
+
+ /*
+ * 4=1/1/1998 was a Thursday
+ */
+ return (ndays + 4) % 7;
+}
+
+static void
+convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
+{
+ eft->year = wtime->tm_year + 1900;
+ eft->month = wtime->tm_mon + 1;
+ eft->day = wtime->tm_mday;
+ eft->hour = wtime->tm_hour;
+ eft->minute = wtime->tm_min;
+ eft->second = wtime->tm_sec;
+ eft->nanosecond = 0;
+ eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
+ eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
+}
+
+static void
+convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
+{
+ memset(wtime, 0, sizeof(*wtime));
+ wtime->tm_sec = eft->second;
+ wtime->tm_min = eft->minute;
+ wtime->tm_hour = eft->hour;
+ wtime->tm_mday = eft->day;
+ wtime->tm_mon = eft->month - 1;
+ wtime->tm_year = eft->year - 1900;
+
+ /* day of the week [0-6], Sunday=0 */
+ wtime->tm_wday = compute_wday(eft);
+
+ /* day in the year [1-365]*/
+ wtime->tm_yday = compute_yday(eft);
+
+
+ switch (eft->daylight & EFI_ISDST) {
+ case EFI_ISDST:
+ wtime->tm_isdst = 1;
+ break;
+ case EFI_TIME_ADJUST_DAYLIGHT:
+ wtime->tm_isdst = 0;
+ break;
+ default:
+ wtime->tm_isdst = -1;
+ }
+}
+
+static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ efi_time_t eft;
+ efi_status_t status;
+
+ /*
+ * As of EFI v1.10, this call always returns an unsupported status
+ */
+ status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
+ (efi_bool_t *)&wkalrm->pending, &eft);
+
+ if (status != EFI_SUCCESS)
+ return -EINVAL;
+
+ convert_from_efi_time(&eft, &wkalrm->time);
+
+ return rtc_valid_tm(&wkalrm->time);
+}
+
+static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ efi_time_t eft;
+ efi_status_t status;
+
+ convert_to_efi_time(&wkalrm->time, &eft);
+
+ /*
+ * XXX Fixme:
+ * As of EFI 0.92 with the firmware I have on my
+ * machine this call does not seem to work quite
+ * right
+ *
+ * As of v1.10, this call always returns an unsupported status
+ */
+ status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
+
+ printk(KERN_WARNING "write status is %d\n", (int)status);
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static int efi_read_time(struct device *dev, struct rtc_time *tm)
+{
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
+
+ status = efi.get_time(&eft, &cap);
+
+ if (status != EFI_SUCCESS) {
+ /* should never happen */
+ printk(KERN_ERR "efitime: can't read time\n");
+ return -EINVAL;
+ }
+
+ convert_from_efi_time(&eft, tm);
+
+ return rtc_valid_tm(tm);
+}
+
+static int efi_set_time(struct device *dev, struct rtc_time *tm)
+{
+ efi_status_t status;
+ efi_time_t eft;
+
+ convert_to_efi_time(tm, &eft);
+
+ status = efi.set_time(&eft);
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static const struct rtc_class_ops efi_rtc_ops = {
+ .read_time = efi_read_time,
+ .set_time = efi_set_time,
+ .read_alarm = efi_read_alarm,
+ .set_alarm = efi_set_alarm,
+};
+
+static int __devinit efi_rtc_probe(struct platform_device *dev)
+{
+ struct rtc_device *rtc;
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ int err = PTR_ERR(rtc);
+ kfree(rtc);
+ return err;
+ }
+
+ platform_set_drvdata(dev, rtc);
+
+ return 0;
+}
+
+static int __devexit efi_rtc_remove(struct platform_device *dev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ rtc_device_unregister(rtc);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct platform_driver efi_rtc_driver = {
+ .driver = {
+ .name = "rtc-efi",
+ .owner = THIS_MODULE,
+ },
+ .probe = efi_rtc_probe,
+ .remove = __devexit_p(efi_rtc_remove),
+};
+
+static int __init efi_rtc_init(void)
+{
+ return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
+}
+
+static void __exit efi_rtc_exit(void)
+{
+ platform_driver_unregister(&efi_rtc_driver);
+}
+
+module_init(efi_rtc_init);
+module_exit(efi_rtc_exit);
+
+MODULE_AUTHOR("dann frazier <dannf@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EFI RTC driver");
--
1.5.6.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [rtc-linux] [PATCH] add rtc platform driver for EFI
2009-01-14 1:17 ` dann frazier
@ 2009-01-14 1:30 ` Alessandro Zummo
2009-01-14 4:13 ` dann frazier
0 siblings, 1 reply; 16+ messages in thread
From: Alessandro Zummo @ 2009-01-14 1:30 UTC (permalink / raw)
To: rtc-linux
Cc: dannf, Andrew Morton, linux-ia64, linux-kernel, stephane eranian
On Tue, 13 Jan 2009 18:17:19 -0700
dann frazier <dannf@hp.com> wrote:
Hi Dann,
thanks for doing the changes that Andrew and I requested. There are
still a few errors:
> Munge Stephane Eranian's efirtc.c code into an rtc platform driver
>
> Signed-off-by: dann frazier <dannf@hp.com>
> ---
> arch/ia64/kernel/time.c | 16 +++
> drivers/rtc/Kconfig | 10 ++
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-efi.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 272 insertions(+), 0 deletions(-)
> create mode 100644 drivers/rtc/rtc-efi.c
>
> diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
> index f0ebb34..558051c 100644
> --- a/arch/ia64/kernel/time.c
> +++ b/arch/ia64/kernel/time.c
> @@ -20,6 +20,7 @@
> #include <linux/efi.h>
> #include <linux/timex.h>
> #include <linux/clocksource.h>
> +#include <linux/platform_device.h>
>
> #include <asm/machvec.h>
> #include <asm/delay.h>
> @@ -405,6 +406,21 @@ static struct irqaction timer_irqaction = {
> .name = "timer"
> };
>
> +static struct platform_device rtc_efi_dev = {
> + .name = "rtc-efi",
> + .id = -1,
> +};
> +
> +static int __init rtc_init(void)
> +{
> + if (platform_device_register(&rtc_efi_dev) < 0)
> + printk(KERN_ERR "unable to register rtc device...\n");
> +
> + /* not necessarily an error */
> + return 0;
> +}
> +module_init(rtc_init);
> +
> void __init
> time_init (void)
> {
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index cced4d1..56cc98f 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -434,6 +434,16 @@ config RTC_DRV_DS1742
> This driver can also be built as a module. If so, the module
> will be called rtc-ds1742.
>
> +config RTC_DRV_EFI
> + tristate "EFI RTC"
> + depends on IA64
> + help
> + If you say yes here you will get support for the EFI
> + Real Time Clock.
> +
> + This driver can also be built as a module. If so, the module
> + will be called rtc-efi.
> +
> config RTC_DRV_STK17TA8
> tristate "Simtek STK17TA8"
> depends on RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 6e28021..7256ce8 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
> obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
> obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
> obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
> +obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
> obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
> obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
> obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
> diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
> new file mode 100644
> index 0000000..ddf0459
> --- /dev/null
> +++ b/drivers/rtc/rtc-efi.c
> @@ -0,0 +1,245 @@
> +/*
> + * rtc-efi: RTC Class Driver for EFI-based systems
> + *
> + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
> + *
> + * Author: dann frazier <dannf@hp.com>
> + * Based on efirtc.c by Stephane Eranian
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/time.h>
> +#include <linux/platform_device.h>
where's linux/rtc.h ?
> +
> +#include <linux/efi.h>
> +
> +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
> +/*
> + * EFI Epoch is 1/1/1998
> + */
> +#define EFI_RTC_EPOCH 1998
> +
> +#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
> +
> +/*
> + * returns day of the year [0-365]
> + */
> +static inline int
> +compute_yday(efi_time_t *eft)
> +{
> + /* efi_time_t.month is in the [1-12] so, we need -1 */
> + return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
> +}
> +/*
> + * returns day of the week [0-6] 0=Sunday
> + *
> + * Don't try to provide a year that's before 1998, please !
> + */
> +static int
> +compute_wday(efi_time_t *eft)
> +{
> + int y;
> + int ndays = 0;
> +
> + if (eft->year < 1998) {
> + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
> + return -1;
> + }
> +
> + for (y = EFI_RTC_EPOCH; y < eft->year; y++)
> + ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
> +
> + ndays += compute_yday(eft);
> +
> + /*
> + * 4=1/1/1998 was a Thursday
> + */
> + return (ndays + 4) % 7;
> +}
> +
> +static void
> +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
> +{
> + eft->year = wtime->tm_year + 1900;
> + eft->month = wtime->tm_mon + 1;
> + eft->day = wtime->tm_mday;
> + eft->hour = wtime->tm_hour;
> + eft->minute = wtime->tm_min;
> + eft->second = wtime->tm_sec;
> + eft->nanosecond = 0;
> + eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
> + eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
> +}
> +
> +static void
> +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
> +{
> + memset(wtime, 0, sizeof(*wtime));
> + wtime->tm_sec = eft->second;
> + wtime->tm_min = eft->minute;
> + wtime->tm_hour = eft->hour;
> + wtime->tm_mday = eft->day;
> + wtime->tm_mon = eft->month - 1;
> + wtime->tm_year = eft->year - 1900;
> +
> + /* day of the week [0-6], Sunday=0 */
> + wtime->tm_wday = compute_wday(eft);
> +
> + /* day in the year [1-365]*/
> + wtime->tm_yday = compute_yday(eft);
> +
> +
> + switch (eft->daylight & EFI_ISDST) {
> + case EFI_ISDST:
> + wtime->tm_isdst = 1;
> + break;
> + case EFI_TIME_ADJUST_DAYLIGHT:
> + wtime->tm_isdst = 0;
> + break;
> + default:
> + wtime->tm_isdst = -1;
> + }
> +}
> +
> +static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> +{
> + efi_time_t eft;
> + efi_status_t status;
> +
> + /*
> + * As of EFI v1.10, this call always returns an unsupported status
> + */
> + status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
> + (efi_bool_t *)&wkalrm->pending, &eft);
> +
> + if (status != EFI_SUCCESS)
> + return -EINVAL;
> +
> + convert_from_efi_time(&eft, &wkalrm->time);
> +
> + return rtc_valid_tm(&wkalrm->time);
> +}
> +
> +static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> +{
> + efi_time_t eft;
> + efi_status_t status;
> +
> + convert_to_efi_time(&wkalrm->time, &eft);
> +
> + /*
> + * XXX Fixme:
> + * As of EFI 0.92 with the firmware I have on my
> + * machine this call does not seem to work quite
> + * right
> + *
> + * As of v1.10, this call always returns an unsupported status
> + */
> + status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
> +
> + printk(KERN_WARNING "write status is %d\n", (int)status);
> +
> + return status == EFI_SUCCESS ? 0 : -EINVAL;
> +}
> +
> +static int efi_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + efi_status_t status;
> + efi_time_t eft;
> + efi_time_cap_t cap;
> +
> + status = efi.get_time(&eft, &cap);
> +
> + if (status != EFI_SUCCESS) {
> + /* should never happen */
> + printk(KERN_ERR "efitime: can't read time\n");
> + return -EINVAL;
> + }
> +
> + convert_from_efi_time(&eft, tm);
> +
> + return rtc_valid_tm(tm);
> +}
> +
> +static int efi_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + efi_status_t status;
> + efi_time_t eft;
> +
> + convert_to_efi_time(tm, &eft);
> +
> + status = efi.set_time(&eft);
> +
> + return status == EFI_SUCCESS ? 0 : -EINVAL;
> +}
> +
> +static const struct rtc_class_ops efi_rtc_ops = {
> + .read_time = efi_read_time,
> + .set_time = efi_set_time,
> + .read_alarm = efi_read_alarm,
> + .set_alarm = efi_set_alarm,
> +};
> +
> +static int __devinit efi_rtc_probe(struct platform_device *dev)
__init
> +{
> + struct rtc_device *rtc;
> +
> + rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
> + if (!rtc)
> + return -ENOMEM;
you are allocating memory
> + rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
> + THIS_MODULE);
and then overwriting it. you don't need kzalloc/kree. the rtc subsystem
will give you back a valid pointer which will be freed
when unregistering.
> + if (IS_ERR(rtc)) {
> + int err = PTR_ERR(rtc);
> + kfree(rtc);
> + return err;
> + }
> +
> + platform_set_drvdata(dev, rtc);
> +
> + return 0;
> +}
> +
> +static int __devexit efi_rtc_remove(struct platform_device *dev)
__exit , you are using platform_driver_probe
> +{
> + struct rtc_device *rtc = platform_get_drvdata(dev);
> +
> + rtc_device_unregister(rtc);
> + kfree(rtc);
ditto.
> +
> + return 0;
> +}
> +
> +static struct platform_driver efi_rtc_driver = {
> + .driver = {
> + .name = "rtc-efi",
> + .owner = THIS_MODULE,
> + },
> + .probe = efi_rtc_probe,
> + .remove = __devexit_p(efi_rtc_remove),
__exit_p
> +};
> +
> +static int __init efi_rtc_init(void)
> +{
> + return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
> +}
> +
> +static void __exit efi_rtc_exit(void)
> +{
> + platform_driver_unregister(&efi_rtc_driver);
> +}
> +
> +module_init(efi_rtc_init);
> +module_exit(efi_rtc_exit);
> +
> +MODULE_AUTHOR("dann frazier <dannf@hp.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("EFI RTC driver");
> --
> 1.5.6.5
>
>
> --~--~---------~--~----~------------~-------~--~----~
> You received this message because you are subscribed to "rtc-linux".
> Membership options at http://groups.google.com/group/rtc-linux .
> Please read http://groups.google.com/group/rtc-linux/web/checklist
> before submitting a driver.
> -~----------~----~----~----~------~----~------~--~---
>
--
Best regards,
Alessandro Zummo,
Tower Technologies - Torino, Italy
http://www.towertech.it
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rtc-linux] [PATCH] add rtc platform driver for EFI
2009-01-14 1:30 ` [rtc-linux] " Alessandro Zummo
@ 2009-01-14 4:13 ` dann frazier
2009-01-14 4:33 ` dann frazier
0 siblings, 1 reply; 16+ messages in thread
From: dann frazier @ 2009-01-14 4:13 UTC (permalink / raw)
To: Alessandro Zummo
Cc: rtc-linux, Andrew Morton, linux-ia64, linux-kernel,
stephane eranian
On Wed, Jan 14, 2009 at 02:30:55AM +0100, Alessandro Zummo wrote:
> On Tue, 13 Jan 2009 18:17:19 -0700
> dann frazier <dannf@hp.com> wrote:
>
> Hi Dann,
>
> thanks for doing the changes that Andrew and I requested. There are
> still a few errors:
Great, thanks again! Updated patch will follow.
--
dann frazier
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH] add rtc platform driver for EFI
2009-01-14 4:13 ` dann frazier
@ 2009-01-14 4:33 ` dann frazier
2009-01-14 10:57 ` Alessandro Zummo
0 siblings, 1 reply; 16+ messages in thread
From: dann frazier @ 2009-01-14 4:33 UTC (permalink / raw)
To: Alessandro Zummo
Cc: rtc-linux, Andrew Morton, linux-ia64, linux-kernel,
stephane eranian
Munge Stephane Eranian's efirtc.c code into an rtc platform driver
Signed-off-by: dann frazier <dannf@hp.com>
---
arch/ia64/kernel/time.c | 16 +++
drivers/rtc/Kconfig | 10 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-efi.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 267 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-efi.c
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index f0ebb34..558051c 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -20,6 +20,7 @@
#include <linux/efi.h>
#include <linux/timex.h>
#include <linux/clocksource.h>
+#include <linux/platform_device.h>
#include <asm/machvec.h>
#include <asm/delay.h>
@@ -405,6 +406,21 @@ static struct irqaction timer_irqaction = {
.name = "timer"
};
+static struct platform_device rtc_efi_dev = {
+ .name = "rtc-efi",
+ .id = -1,
+};
+
+static int __init rtc_init(void)
+{
+ if (platform_device_register(&rtc_efi_dev) < 0)
+ printk(KERN_ERR "unable to register rtc device...\n");
+
+ /* not necessarily an error */
+ return 0;
+}
+module_init(rtc_init);
+
void __init
time_init (void)
{
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cced4d1..56cc98f 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -434,6 +434,16 @@ config RTC_DRV_DS1742
This driver can also be built as a module. If so, the module
will be called rtc-ds1742.
+config RTC_DRV_EFI
+ tristate "EFI RTC"
+ depends on IA64
+ help
+ If you say yes here you will get support for the EFI
+ Real Time Clock.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-efi.
+
config RTC_DRV_STK17TA8
tristate "Simtek STK17TA8"
depends on RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6e28021..7256ce8 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
+obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
new file mode 100644
index 0000000..2c98c35
--- /dev/null
+++ b/drivers/rtc/rtc-efi.c
@@ -0,0 +1,240 @@
+/*
+ * rtc-efi: RTC Class Driver for EFI-based systems
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Author: dann frazier <dannf@hp.com>
+ * Based on efirtc.c by Stephane Eranian
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/efi.h>
+
+#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
+/*
+ * EFI Epoch is 1/1/1998
+ */
+#define EFI_RTC_EPOCH 1998
+
+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+
+/*
+ * returns day of the year [0-365]
+ */
+static inline int
+compute_yday(efi_time_t *eft)
+{
+ /* efi_time_t.month is in the [1-12] so, we need -1 */
+ return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
+}
+/*
+ * returns day of the week [0-6] 0=Sunday
+ *
+ * Don't try to provide a year that's before 1998, please !
+ */
+static int
+compute_wday(efi_time_t *eft)
+{
+ int y;
+ int ndays = 0;
+
+ if (eft->year < 1998) {
+ printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+ return -1;
+ }
+
+ for (y = EFI_RTC_EPOCH; y < eft->year; y++)
+ ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
+
+ ndays += compute_yday(eft);
+
+ /*
+ * 4=1/1/1998 was a Thursday
+ */
+ return (ndays + 4) % 7;
+}
+
+static void
+convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
+{
+ eft->year = wtime->tm_year + 1900;
+ eft->month = wtime->tm_mon + 1;
+ eft->day = wtime->tm_mday;
+ eft->hour = wtime->tm_hour;
+ eft->minute = wtime->tm_min;
+ eft->second = wtime->tm_sec;
+ eft->nanosecond = 0;
+ eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
+ eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
+}
+
+static void
+convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
+{
+ memset(wtime, 0, sizeof(*wtime));
+ wtime->tm_sec = eft->second;
+ wtime->tm_min = eft->minute;
+ wtime->tm_hour = eft->hour;
+ wtime->tm_mday = eft->day;
+ wtime->tm_mon = eft->month - 1;
+ wtime->tm_year = eft->year - 1900;
+
+ /* day of the week [0-6], Sunday=0 */
+ wtime->tm_wday = compute_wday(eft);
+
+ /* day in the year [1-365]*/
+ wtime->tm_yday = compute_yday(eft);
+
+
+ switch (eft->daylight & EFI_ISDST) {
+ case EFI_ISDST:
+ wtime->tm_isdst = 1;
+ break;
+ case EFI_TIME_ADJUST_DAYLIGHT:
+ wtime->tm_isdst = 0;
+ break;
+ default:
+ wtime->tm_isdst = -1;
+ }
+}
+
+static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ efi_time_t eft;
+ efi_status_t status;
+
+ /*
+ * As of EFI v1.10, this call always returns an unsupported status
+ */
+ status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
+ (efi_bool_t *)&wkalrm->pending, &eft);
+
+ if (status != EFI_SUCCESS)
+ return -EINVAL;
+
+ convert_from_efi_time(&eft, &wkalrm->time);
+
+ return rtc_valid_tm(&wkalrm->time);
+}
+
+static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ efi_time_t eft;
+ efi_status_t status;
+
+ convert_to_efi_time(&wkalrm->time, &eft);
+
+ /*
+ * XXX Fixme:
+ * As of EFI 0.92 with the firmware I have on my
+ * machine this call does not seem to work quite
+ * right
+ *
+ * As of v1.10, this call always returns an unsupported status
+ */
+ status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
+
+ printk(KERN_WARNING "write status is %d\n", (int)status);
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static int efi_read_time(struct device *dev, struct rtc_time *tm)
+{
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
+
+ status = efi.get_time(&eft, &cap);
+
+ if (status != EFI_SUCCESS) {
+ /* should never happen */
+ printk(KERN_ERR "efitime: can't read time\n");
+ return -EINVAL;
+ }
+
+ convert_from_efi_time(&eft, tm);
+
+ return rtc_valid_tm(tm);
+}
+
+static int efi_set_time(struct device *dev, struct rtc_time *tm)
+{
+ efi_status_t status;
+ efi_time_t eft;
+
+ convert_to_efi_time(tm, &eft);
+
+ status = efi.set_time(&eft);
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static const struct rtc_class_ops efi_rtc_ops = {
+ .read_time = efi_read_time,
+ .set_time = efi_set_time,
+ .read_alarm = efi_read_alarm,
+ .set_alarm = efi_set_alarm,
+};
+
+static int __init efi_rtc_probe(struct platform_device *dev)
+{
+ struct rtc_device *rtc;
+
+ rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ int err = PTR_ERR(rtc);
+ return err;
+ }
+
+ platform_set_drvdata(dev, rtc);
+
+ return 0;
+}
+
+static int __exit efi_rtc_remove(struct platform_device *dev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ rtc_device_unregister(rtc);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct platform_driver efi_rtc_driver = {
+ .driver = {
+ .name = "rtc-efi",
+ .owner = THIS_MODULE,
+ },
+ .probe = efi_rtc_probe,
+ .remove = __exit_p(efi_rtc_remove),
+};
+
+static int __init efi_rtc_init(void)
+{
+ return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
+}
+
+static void __exit efi_rtc_exit(void)
+{
+ platform_driver_unregister(&efi_rtc_driver);
+}
+
+module_init(efi_rtc_init);
+module_exit(efi_rtc_exit);
+
+MODULE_AUTHOR("dann frazier <dannf@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EFI RTC driver");
--
1.5.6.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] add rtc platform driver for EFI
2009-01-14 4:33 ` dann frazier
@ 2009-01-14 10:57 ` Alessandro Zummo
2009-01-14 17:37 ` dann frazier
2009-01-14 17:39 ` dann frazier
0 siblings, 2 replies; 16+ messages in thread
From: Alessandro Zummo @ 2009-01-14 10:57 UTC (permalink / raw)
To: dann frazier
Cc: rtc-linux, Andrew Morton, linux-ia64, linux-kernel,
stephane eranian
On Tue, 13 Jan 2009 21:33:38 -0700
dann frazier <dannf@hp.com> wrote:
> Munge Stephane Eranian's efirtc.c code into an rtc platform driver
almost there :) see below
> Signed-off-by: dann frazier <dannf@hp.com>
> ---
> arch/ia64/kernel/time.c | 16 +++
> drivers/rtc/Kconfig | 10 ++
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-efi.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 267 insertions(+), 0 deletions(-)
> create mode 100644 drivers/rtc/rtc-efi.c
>
> diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
> index f0ebb34..558051c 100644
> --- a/arch/ia64/kernel/time.c
> +++ b/arch/ia64/kernel/time.c
> @@ -20,6 +20,7 @@
> #include <linux/efi.h>
> #include <linux/timex.h>
> #include <linux/clocksource.h>
> +#include <linux/platform_device.h>
>
> #include <asm/machvec.h>
> #include <asm/delay.h>
> @@ -405,6 +406,21 @@ static struct irqaction timer_irqaction = {
> .name = "timer"
> };
>
> +static struct platform_device rtc_efi_dev = {
> + .name = "rtc-efi",
> + .id = -1,
> +};
> +
> +static int __init rtc_init(void)
> +{
> + if (platform_device_register(&rtc_efi_dev) < 0)
> + printk(KERN_ERR "unable to register rtc device...\n");
> +
> + /* not necessarily an error */
> + return 0;
> +}
> +module_init(rtc_init);
> +
> void __init
> time_init (void)
> {
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index cced4d1..56cc98f 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -434,6 +434,16 @@ config RTC_DRV_DS1742
> This driver can also be built as a module. If so, the module
> will be called rtc-ds1742.
>
> +config RTC_DRV_EFI
> + tristate "EFI RTC"
> + depends on IA64
> + help
> + If you say yes here you will get support for the EFI
> + Real Time Clock.
> +
> + This driver can also be built as a module. If so, the module
> + will be called rtc-efi.
> +
> config RTC_DRV_STK17TA8
> tristate "Simtek STK17TA8"
> depends on RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 6e28021..7256ce8 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
> obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
> obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
> obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
> +obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
> obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
> obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
> obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
> diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
> new file mode 100644
> index 0000000..2c98c35
> --- /dev/null
> +++ b/drivers/rtc/rtc-efi.c
> @@ -0,0 +1,240 @@
> +/*
> + * rtc-efi: RTC Class Driver for EFI-based systems
> + *
> + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
> + *
> + * Author: dann frazier <dannf@hp.com>
> + * Based on efirtc.c by Stephane Eranian
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/time.h>
> +#include <linux/platform_device.h>
> +#include <linux/rtc.h>
> +#include <linux/efi.h>
> +
> +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
> +/*
> + * EFI Epoch is 1/1/1998
> + */
> +#define EFI_RTC_EPOCH 1998
> +
> +#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
> +
> +/*
> + * returns day of the year [0-365]
> + */
> +static inline int
> +compute_yday(efi_time_t *eft)
> +{
> + /* efi_time_t.month is in the [1-12] so, we need -1 */
> + return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
> +}
> +/*
> + * returns day of the week [0-6] 0=Sunday
> + *
> + * Don't try to provide a year that's before 1998, please !
> + */
> +static int
> +compute_wday(efi_time_t *eft)
> +{
> + int y;
> + int ndays = 0;
> +
> + if (eft->year < 1998) {
> + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
> + return -1;
> + }
> +
> + for (y = EFI_RTC_EPOCH; y < eft->year; y++)
> + ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
> +
> + ndays += compute_yday(eft);
> +
> + /*
> + * 4=1/1/1998 was a Thursday
> + */
> + return (ndays + 4) % 7;
> +}
> +
> +static void
> +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
> +{
> + eft->year = wtime->tm_year + 1900;
> + eft->month = wtime->tm_mon + 1;
> + eft->day = wtime->tm_mday;
> + eft->hour = wtime->tm_hour;
> + eft->minute = wtime->tm_min;
> + eft->second = wtime->tm_sec;
> + eft->nanosecond = 0;
> + eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
> + eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
> +}
> +
> +static void
> +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
> +{
> + memset(wtime, 0, sizeof(*wtime));
> + wtime->tm_sec = eft->second;
> + wtime->tm_min = eft->minute;
> + wtime->tm_hour = eft->hour;
> + wtime->tm_mday = eft->day;
> + wtime->tm_mon = eft->month - 1;
> + wtime->tm_year = eft->year - 1900;
> +
> + /* day of the week [0-6], Sunday=0 */
> + wtime->tm_wday = compute_wday(eft);
> +
> + /* day in the year [1-365]*/
> + wtime->tm_yday = compute_yday(eft);
> +
> +
> + switch (eft->daylight & EFI_ISDST) {
> + case EFI_ISDST:
> + wtime->tm_isdst = 1;
> + break;
> + case EFI_TIME_ADJUST_DAYLIGHT:
> + wtime->tm_isdst = 0;
> + break;
> + default:
> + wtime->tm_isdst = -1;
> + }
> +}
> +
> +static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> +{
> + efi_time_t eft;
> + efi_status_t status;
> +
> + /*
> + * As of EFI v1.10, this call always returns an unsupported status
> + */
> + status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
> + (efi_bool_t *)&wkalrm->pending, &eft);
> +
> + if (status != EFI_SUCCESS)
> + return -EINVAL;
> +
> + convert_from_efi_time(&eft, &wkalrm->time);
> +
> + return rtc_valid_tm(&wkalrm->time);
> +}
> +
> +static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
> +{
> + efi_time_t eft;
> + efi_status_t status;
> +
> + convert_to_efi_time(&wkalrm->time, &eft);
> +
> + /*
> + * XXX Fixme:
> + * As of EFI 0.92 with the firmware I have on my
> + * machine this call does not seem to work quite
> + * right
> + *
> + * As of v1.10, this call always returns an unsupported status
> + */
> + status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
> +
> + printk(KERN_WARNING "write status is %d\n", (int)status);
> +
> + return status == EFI_SUCCESS ? 0 : -EINVAL;
> +}
> +
> +static int efi_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + efi_status_t status;
> + efi_time_t eft;
> + efi_time_cap_t cap;
> +
> + status = efi.get_time(&eft, &cap);
> +
> + if (status != EFI_SUCCESS) {
> + /* should never happen */
> + printk(KERN_ERR "efitime: can't read time\n");
> + return -EINVAL;
> + }
> +
> + convert_from_efi_time(&eft, tm);
> +
> + return rtc_valid_tm(tm);
> +}
> +
> +static int efi_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + efi_status_t status;
> + efi_time_t eft;
> +
> + convert_to_efi_time(tm, &eft);
> +
> + status = efi.set_time(&eft);
> +
> + return status == EFI_SUCCESS ? 0 : -EINVAL;
> +}
> +
> +static const struct rtc_class_ops efi_rtc_ops = {
> + .read_time = efi_read_time,
> + .set_time = efi_set_time,
> + .read_alarm = efi_read_alarm,
> + .set_alarm = efi_set_alarm,
> +};
> +
> +static int __init efi_rtc_probe(struct platform_device *dev)
> +{
> + struct rtc_device *rtc;
> +
> + rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
> + THIS_MODULE);
> + if (IS_ERR(rtc)) {
> + int err = PTR_ERR(rtc);
> + return err;
> + }
if (IS_ERR(rtc))
return PTR_ERR(rtc);
> +
> + platform_set_drvdata(dev, rtc);
> +
> + return 0;
> +}
> +
> +static int __exit efi_rtc_remove(struct platform_device *dev)
> +{
> + struct rtc_device *rtc = platform_get_drvdata(dev);
> +
> + rtc_device_unregister(rtc);
> + kfree(rtc);
don't free it!!
> +
> + return 0;
> +}
> +
> +static struct platform_driver efi_rtc_driver = {
> + .driver = {
> + .name = "rtc-efi",
> + .owner = THIS_MODULE,
> + },
> + .probe = efi_rtc_probe,
> + .remove = __exit_p(efi_rtc_remove),
> +};
> +
> +static int __init efi_rtc_init(void)
> +{
> + return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
> +}
> +
> +static void __exit efi_rtc_exit(void)
> +{
> + platform_driver_unregister(&efi_rtc_driver);
> +}
> +
> +module_init(efi_rtc_init);
> +module_exit(efi_rtc_exit);
> +
> +MODULE_AUTHOR("dann frazier <dannf@hp.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("EFI RTC driver");
> --
> 1.5.6.5
>
--
Best regards,
Alessandro Zummo,
Tower Technologies - Torino, Italy
http://www.towertech.it
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH] add rtc platform driver for EFI
2009-01-14 10:57 ` Alessandro Zummo
@ 2009-01-14 17:37 ` dann frazier
2009-01-14 21:25 ` Andrew Morton
2009-01-14 17:39 ` dann frazier
1 sibling, 1 reply; 16+ messages in thread
From: dann frazier @ 2009-01-14 17:37 UTC (permalink / raw)
To: Alessandro Zummo
Cc: rtc-linux, Andrew Morton, linux-ia64, linux-kernel,
stephane eranian
Munge Stephane Eranian's efirtc.c code into an rtc platform driver
Signed-off-by: dann frazier <dannf@hp.com>
---
arch/ia64/kernel/time.c | 16 +++
drivers/rtc/Kconfig | 10 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-efi.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 264 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-efi.c
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index f0ebb34..558051c 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -20,6 +20,7 @@
#include <linux/efi.h>
#include <linux/timex.h>
#include <linux/clocksource.h>
+#include <linux/platform_device.h>
#include <asm/machvec.h>
#include <asm/delay.h>
@@ -405,6 +406,21 @@ static struct irqaction timer_irqaction = {
.name = "timer"
};
+static struct platform_device rtc_efi_dev = {
+ .name = "rtc-efi",
+ .id = -1,
+};
+
+static int __init rtc_init(void)
+{
+ if (platform_device_register(&rtc_efi_dev) < 0)
+ printk(KERN_ERR "unable to register rtc device...\n");
+
+ /* not necessarily an error */
+ return 0;
+}
+module_init(rtc_init);
+
void __init
time_init (void)
{
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cced4d1..56cc98f 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -434,6 +434,16 @@ config RTC_DRV_DS1742
This driver can also be built as a module. If so, the module
will be called rtc-ds1742.
+config RTC_DRV_EFI
+ tristate "EFI RTC"
+ depends on IA64
+ help
+ If you say yes here you will get support for the EFI
+ Real Time Clock.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-efi.
+
config RTC_DRV_STK17TA8
tristate "Simtek STK17TA8"
depends on RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6e28021..7256ce8 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
+obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
new file mode 100644
index 0000000..cf37810
--- /dev/null
+++ b/drivers/rtc/rtc-efi.c
@@ -0,0 +1,237 @@
+/*
+ * rtc-efi: RTC Class Driver for EFI-based systems
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Author: dann frazier <dannf@hp.com>
+ * Based on efirtc.c by Stephane Eranian
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/efi.h>
+
+#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
+/*
+ * EFI Epoch is 1/1/1998
+ */
+#define EFI_RTC_EPOCH 1998
+
+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+
+/*
+ * returns day of the year [0-365]
+ */
+static inline int
+compute_yday(efi_time_t *eft)
+{
+ /* efi_time_t.month is in the [1-12] so, we need -1 */
+ return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
+}
+/*
+ * returns day of the week [0-6] 0=Sunday
+ *
+ * Don't try to provide a year that's before 1998, please !
+ */
+static int
+compute_wday(efi_time_t *eft)
+{
+ int y;
+ int ndays = 0;
+
+ if (eft->year < 1998) {
+ printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+ return -1;
+ }
+
+ for (y = EFI_RTC_EPOCH; y < eft->year; y++)
+ ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
+
+ ndays += compute_yday(eft);
+
+ /*
+ * 4=1/1/1998 was a Thursday
+ */
+ return (ndays + 4) % 7;
+}
+
+static void
+convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
+{
+ eft->year = wtime->tm_year + 1900;
+ eft->month = wtime->tm_mon + 1;
+ eft->day = wtime->tm_mday;
+ eft->hour = wtime->tm_hour;
+ eft->minute = wtime->tm_min;
+ eft->second = wtime->tm_sec;
+ eft->nanosecond = 0;
+ eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
+ eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
+}
+
+static void
+convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
+{
+ memset(wtime, 0, sizeof(*wtime));
+ wtime->tm_sec = eft->second;
+ wtime->tm_min = eft->minute;
+ wtime->tm_hour = eft->hour;
+ wtime->tm_mday = eft->day;
+ wtime->tm_mon = eft->month - 1;
+ wtime->tm_year = eft->year - 1900;
+
+ /* day of the week [0-6], Sunday=0 */
+ wtime->tm_wday = compute_wday(eft);
+
+ /* day in the year [1-365]*/
+ wtime->tm_yday = compute_yday(eft);
+
+
+ switch (eft->daylight & EFI_ISDST) {
+ case EFI_ISDST:
+ wtime->tm_isdst = 1;
+ break;
+ case EFI_TIME_ADJUST_DAYLIGHT:
+ wtime->tm_isdst = 0;
+ break;
+ default:
+ wtime->tm_isdst = -1;
+ }
+}
+
+static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ efi_time_t eft;
+ efi_status_t status;
+
+ /*
+ * As of EFI v1.10, this call always returns an unsupported status
+ */
+ status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
+ (efi_bool_t *)&wkalrm->pending, &eft);
+
+ if (status != EFI_SUCCESS)
+ return -EINVAL;
+
+ convert_from_efi_time(&eft, &wkalrm->time);
+
+ return rtc_valid_tm(&wkalrm->time);
+}
+
+static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ efi_time_t eft;
+ efi_status_t status;
+
+ convert_to_efi_time(&wkalrm->time, &eft);
+
+ /*
+ * XXX Fixme:
+ * As of EFI 0.92 with the firmware I have on my
+ * machine this call does not seem to work quite
+ * right
+ *
+ * As of v1.10, this call always returns an unsupported status
+ */
+ status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
+
+ printk(KERN_WARNING "write status is %d\n", (int)status);
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static int efi_read_time(struct device *dev, struct rtc_time *tm)
+{
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
+
+ status = efi.get_time(&eft, &cap);
+
+ if (status != EFI_SUCCESS) {
+ /* should never happen */
+ printk(KERN_ERR "efitime: can't read time\n");
+ return -EINVAL;
+ }
+
+ convert_from_efi_time(&eft, tm);
+
+ return rtc_valid_tm(tm);
+}
+
+static int efi_set_time(struct device *dev, struct rtc_time *tm)
+{
+ efi_status_t status;
+ efi_time_t eft;
+
+ convert_to_efi_time(tm, &eft);
+
+ status = efi.set_time(&eft);
+
+ return status == EFI_SUCCESS ? 0 : -EINVAL;
+}
+
+static const struct rtc_class_ops efi_rtc_ops = {
+ .read_time = efi_read_time,
+ .set_time = efi_set_time,
+ .read_alarm = efi_read_alarm,
+ .set_alarm = efi_set_alarm,
+};
+
+static int __init efi_rtc_probe(struct platform_device *dev)
+{
+ struct rtc_device *rtc;
+
+ rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ platform_set_drvdata(dev, rtc);
+
+ return 0;
+}
+
+static int __exit efi_rtc_remove(struct platform_device *dev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ rtc_device_unregister(rtc);
+
+ return 0;
+}
+
+static struct platform_driver efi_rtc_driver = {
+ .driver = {
+ .name = "rtc-efi",
+ .owner = THIS_MODULE,
+ },
+ .probe = efi_rtc_probe,
+ .remove = __exit_p(efi_rtc_remove),
+};
+
+static int __init efi_rtc_init(void)
+{
+ return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
+}
+
+static void __exit efi_rtc_exit(void)
+{
+ platform_driver_unregister(&efi_rtc_driver);
+}
+
+module_init(efi_rtc_init);
+module_exit(efi_rtc_exit);
+
+MODULE_AUTHOR("dann frazier <dannf@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EFI RTC driver");
--
1.5.6.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] add rtc platform driver for EFI
2009-01-14 10:57 ` Alessandro Zummo
2009-01-14 17:37 ` dann frazier
@ 2009-01-14 17:39 ` dann frazier
1 sibling, 0 replies; 16+ messages in thread
From: dann frazier @ 2009-01-14 17:39 UTC (permalink / raw)
To: Alessandro Zummo
Cc: rtc-linux, Andrew Morton, linux-ia64, linux-kernel,
stephane eranian
On Wed, Jan 14, 2009 at 11:57:28AM +0100, Alessandro Zummo wrote:
> On Tue, 13 Jan 2009 21:33:38 -0700
> dann frazier <dannf@hp.com> wrote:
>
> > Munge Stephane Eranian's efirtc.c code into an rtc platform driver
>
> almost there :) see below
Thanks - another patch sent.
By the way, what do you think about moving the LEAP_YEAR macro in
rtc-lib into rtc.h to avoid the duplicate definition?
--
dann frazier
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] add rtc platform driver for EFI
2009-01-14 17:37 ` dann frazier
@ 2009-01-14 21:25 ` Andrew Morton
2009-01-14 21:39 ` [rtc-linux] " Alessandro Zummo
2009-01-14 21:46 ` dann frazier
0 siblings, 2 replies; 16+ messages in thread
From: Andrew Morton @ 2009-01-14 21:25 UTC (permalink / raw)
To: dann frazier
Cc: alessandro.zummo, rtc-linux, linux-ia64, linux-kernel, eranian
On Wed, 14 Jan 2009 10:37:45 -0700
dann frazier <dannf@dannf.org> wrote:
> +#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
gargh. We should put a tax on #defines to discourage their consumption.
How about we do this:
From: Andrew Morton <akpm@linux-foundation.org>
- the LEAP_YEAR macro is buggy - it references its arg multiple times.
Fix this by turning it into a C function.
- give it a more approriate name
- Move it to rtc.h so that other .c files can use it, instead of copying it.
Cc: dann frazier <dannf@hp.com>
Cc: Alessandro Zummo <alessandro.zummo@towertech.it>
Cc: stephane eranian <eranian@googlemail.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
drivers/rtc/rtc-lib.c | 7 +++----
include/linux/rtc.h | 6 ++++++
2 files changed, 9 insertions(+), 4 deletions(-)
diff -puN drivers/rtc/rtc-lib.c~rtc-convert-leap_year-into-an-inline drivers/rtc/rtc-lib.c
--- a/drivers/rtc/rtc-lib.c~rtc-convert-leap_year-into-an-inline
+++ a/drivers/rtc/rtc-lib.c
@@ -26,14 +26,13 @@ static const unsigned short rtc_ydays[2]
};
#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
-#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
/*
* The number of days in the month.
*/
int rtc_month_days(unsigned int month, unsigned int year)
{
- return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
+ return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
}
EXPORT_SYMBOL(rtc_month_days);
@@ -42,7 +41,7 @@ EXPORT_SYMBOL(rtc_month_days);
*/
int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
{
- return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
+ return rtc_ydays[is_leap_year(year)][month] + day-1;
}
EXPORT_SYMBOL(rtc_year_days);
@@ -66,7 +65,7 @@ void rtc_time_to_tm(unsigned long time,
- LEAPS_THRU_END_OF(1970 - 1);
if (days < 0) {
year -= 1;
- days += 365 + LEAP_YEAR(year);
+ days += 365 + is_leap_year(year);
}
tm->tm_year = year - 1900;
tm->tm_yday = days + 1;
diff -puN include/linux/rtc.h~rtc-convert-leap_year-into-an-inline include/linux/rtc.h
--- a/include/linux/rtc.h~rtc-convert-leap_year-into-an-inline
+++ a/include/linux/rtc.h
@@ -99,6 +99,7 @@ struct rtc_pll_info {
#ifdef __KERNEL__
+#include <linux/types.h>
#include <linux/interrupt.h>
extern int rtc_month_days(unsigned int month, unsigned int year);
@@ -232,6 +233,11 @@ int rtc_register(rtc_task_t *task);
int rtc_unregister(rtc_task_t *task);
int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
+static inline bool is_leap_year(unsigned int year)
+{
+ return (!(year % 4) && (year % 100)) || !(year % 400);
+}
+
#endif /* __KERNEL__ */
#endif /* _LINUX_RTC_H_ */
_
and then we modify your patch thusly:
From: Andrew Morton <akpm@linux-foundation.org>
Use is_leap_year()
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: Alessandro Zummo <alessandro.zummo@towertech.it>
Cc: David Brownell <david-b@pacbell.net>
Cc: dann frazier <dannf@dannf.org>
Cc: dann frazier <dannf@hp.com>
Cc: stephane eranian <eranian@googlemail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
drivers/rtc/rtc-efi.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff -puN arch/ia64/kernel/time.c~rtc-add-platform-driver-for-efi-fix arch/ia64/kernel/time.c
diff -puN drivers/rtc/Kconfig~rtc-add-platform-driver-for-efi-fix drivers/rtc/Kconfig
diff -puN drivers/rtc/Makefile~rtc-add-platform-driver-for-efi-fix drivers/rtc/Makefile
diff -puN drivers/rtc/rtc-efi.c~rtc-add-platform-driver-for-efi-fix drivers/rtc/rtc-efi.c
--- a/drivers/rtc/rtc-efi.c~rtc-add-platform-driver-for-efi-fix
+++ a/drivers/rtc/rtc-efi.c
@@ -26,8 +26,6 @@
*/
#define EFI_RTC_EPOCH 1998
-#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
-
/*
* returns day of the year [0-365]
*/
@@ -54,7 +52,7 @@ compute_wday(efi_time_t *eft)
}
for (y = EFI_RTC_EPOCH; y < eft->year; y++)
- ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
+ ndays += 365 + (is_leap_year(y) ? 1 : 0);
ndays += compute_yday(eft);
_
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [rtc-linux] Re: [PATCH] add rtc platform driver for EFI
2009-01-14 21:25 ` Andrew Morton
@ 2009-01-14 21:39 ` Alessandro Zummo
2009-01-14 21:46 ` dann frazier
1 sibling, 0 replies; 16+ messages in thread
From: Alessandro Zummo @ 2009-01-14 21:39 UTC (permalink / raw)
To: rtc-linux; +Cc: akpm, dann frazier, linux-ia64, linux-kernel, eranian
On Wed, 14 Jan 2009 13:25:54 -0800
Andrew Morton <akpm@linux-foundation.org> wrote:
> From: Andrew Morton <akpm@linux-foundation.org>
>
> - the LEAP_YEAR macro is buggy - it references its arg multiple times.
> Fix this by turning it into a C function.
>
> - give it a more approriate name
>
> - Move it to rtc.h so that other .c files can use it, instead of copying it.
Seems nice! I'll send to Linus :))))
Acked-by: Alessandro Zummo <a.zummo@towertech.it>
--
Best regards,
Alessandro Zummo,
Tower Technologies - Torino, Italy
http://www.towertech.it
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] add rtc platform driver for EFI
2009-01-14 21:25 ` Andrew Morton
2009-01-14 21:39 ` [rtc-linux] " Alessandro Zummo
@ 2009-01-14 21:46 ` dann frazier
1 sibling, 0 replies; 16+ messages in thread
From: dann frazier @ 2009-01-14 21:46 UTC (permalink / raw)
To: Andrew Morton
Cc: alessandro.zummo, rtc-linux, linux-ia64, linux-kernel, eranian
On Wed, Jan 14, 2009 at 01:25:54PM -0800, Andrew Morton wrote:
> On Wed, 14 Jan 2009 10:37:45 -0700
> dann frazier <dannf@dannf.org> wrote:
>
> > +#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
>
> gargh. We should put a tax on #defines to discourage their consumption.
>
>
> How about we do this:
Sounds good to me :)
> From: Andrew Morton <akpm@linux-foundation.org>
>
> - the LEAP_YEAR macro is buggy - it references its arg multiple times.
> Fix this by turning it into a C function.
>
> - give it a more approriate name
>
> - Move it to rtc.h so that other .c files can use it, instead of copying it.
>
> Cc: dann frazier <dannf@hp.com>
> Cc: Alessandro Zummo <alessandro.zummo@towertech.it>
> Cc: stephane eranian <eranian@googlemail.com>
> Cc: "Luck, Tony" <tony.luck@intel.com>
> Cc: David Brownell <david-b@pacbell.net>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
>
> drivers/rtc/rtc-lib.c | 7 +++----
> include/linux/rtc.h | 6 ++++++
> 2 files changed, 9 insertions(+), 4 deletions(-)
>
> diff -puN drivers/rtc/rtc-lib.c~rtc-convert-leap_year-into-an-inline drivers/rtc/rtc-lib.c
> --- a/drivers/rtc/rtc-lib.c~rtc-convert-leap_year-into-an-inline
> +++ a/drivers/rtc/rtc-lib.c
> @@ -26,14 +26,13 @@ static const unsigned short rtc_ydays[2]
> };
>
> #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
> -#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
>
> /*
> * The number of days in the month.
> */
> int rtc_month_days(unsigned int month, unsigned int year)
> {
> - return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
> + return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
> }
> EXPORT_SYMBOL(rtc_month_days);
>
> @@ -42,7 +41,7 @@ EXPORT_SYMBOL(rtc_month_days);
> */
> int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
> {
> - return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
> + return rtc_ydays[is_leap_year(year)][month] + day-1;
> }
> EXPORT_SYMBOL(rtc_year_days);
>
> @@ -66,7 +65,7 @@ void rtc_time_to_tm(unsigned long time,
> - LEAPS_THRU_END_OF(1970 - 1);
> if (days < 0) {
> year -= 1;
> - days += 365 + LEAP_YEAR(year);
> + days += 365 + is_leap_year(year);
> }
> tm->tm_year = year - 1900;
> tm->tm_yday = days + 1;
> diff -puN include/linux/rtc.h~rtc-convert-leap_year-into-an-inline include/linux/rtc.h
> --- a/include/linux/rtc.h~rtc-convert-leap_year-into-an-inline
> +++ a/include/linux/rtc.h
> @@ -99,6 +99,7 @@ struct rtc_pll_info {
>
> #ifdef __KERNEL__
>
> +#include <linux/types.h>
> #include <linux/interrupt.h>
>
> extern int rtc_month_days(unsigned int month, unsigned int year);
> @@ -232,6 +233,11 @@ int rtc_register(rtc_task_t *task);
> int rtc_unregister(rtc_task_t *task);
> int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
>
> +static inline bool is_leap_year(unsigned int year)
> +{
> + return (!(year % 4) && (year % 100)) || !(year % 400);
> +}
> +
> #endif /* __KERNEL__ */
>
> #endif /* _LINUX_RTC_H_ */
> _
>
>
>
> and then we modify your patch thusly:
>
>
> From: Andrew Morton <akpm@linux-foundation.org>
>
> Use is_leap_year()
>
> Cc: "Luck, Tony" <tony.luck@intel.com>
> Cc: Alessandro Zummo <alessandro.zummo@towertech.it>
> Cc: David Brownell <david-b@pacbell.net>
> Cc: dann frazier <dannf@dannf.org>
> Cc: dann frazier <dannf@hp.com>
> Cc: stephane eranian <eranian@googlemail.com>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
>
> drivers/rtc/rtc-efi.c | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff -puN arch/ia64/kernel/time.c~rtc-add-platform-driver-for-efi-fix arch/ia64/kernel/time.c
> diff -puN drivers/rtc/Kconfig~rtc-add-platform-driver-for-efi-fix drivers/rtc/Kconfig
> diff -puN drivers/rtc/Makefile~rtc-add-platform-driver-for-efi-fix drivers/rtc/Makefile
> diff -puN drivers/rtc/rtc-efi.c~rtc-add-platform-driver-for-efi-fix drivers/rtc/rtc-efi.c
> --- a/drivers/rtc/rtc-efi.c~rtc-add-platform-driver-for-efi-fix
> +++ a/drivers/rtc/rtc-efi.c
> @@ -26,8 +26,6 @@
> */
> #define EFI_RTC_EPOCH 1998
>
> -#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
> -
> /*
> * returns day of the year [0-365]
> */
> @@ -54,7 +52,7 @@ compute_wday(efi_time_t *eft)
> }
>
> for (y = EFI_RTC_EPOCH; y < eft->year; y++)
> - ndays += 365 + (LEAP_YEAR(y) ? 1 : 0);
> + ndays += 365 + (is_leap_year(y) ? 1 : 0);
>
> ndays += compute_yday(eft);
>
> _
>
--
dann frazier
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2009-01-14 21:46 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-09 0:56 [PATCH] add rtc platform driver for EFI dann frazier
2009-01-09 2:27 ` [rtc-linux] " Alessandro Zummo
2009-01-09 21:34 ` dann frazier
2009-01-09 21:36 ` dann frazier
2009-01-13 8:39 ` Andrew Morton
2009-01-14 0:00 ` dann frazier
2009-01-14 1:17 ` dann frazier
2009-01-14 1:30 ` [rtc-linux] " Alessandro Zummo
2009-01-14 4:13 ` dann frazier
2009-01-14 4:33 ` dann frazier
2009-01-14 10:57 ` Alessandro Zummo
2009-01-14 17:37 ` dann frazier
2009-01-14 21:25 ` Andrew Morton
2009-01-14 21:39 ` [rtc-linux] " Alessandro Zummo
2009-01-14 21:46 ` dann frazier
2009-01-14 17:39 ` dann frazier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox