diff --git a/debian/changelog b/debian/changelog index 4068dbf45..5af3926f5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +linux-2.6 (2.6.29-5) UNRELEASED; urgency=low + + * [ia64] Backport rtc-efi driver from mainline + + -- dann frazier Mon, 04 May 2009 13:40:51 -0600 + linux-2.6 (2.6.29-4) unstable; urgency=low [ maximilian attems ] diff --git a/debian/config/ia64/config b/debian/config/ia64/config index 362b952ff..13f10b466 100644 --- a/debian/config/ia64/config +++ b/debian/config/ia64/config @@ -91,7 +91,6 @@ CONFIG_SGI_MBCS=m CONFIG_PRINTER=m # CONFIG_LP_CONSOLE is not set CONFIG_PPDEV=m -CONFIG_EFI_RTC=y CONFIG_DTLK=m CONFIG_APPLICOM=m CONFIG_RAW_DRIVER=m @@ -593,6 +592,11 @@ CONFIG_YENTA=m CONFIG_PD6729=m CONFIG_I82092=m +## +## file: drivers/rtc/Kconfig +## +CONFIG_RTC_DRV_EFI=y + ## ## file: drivers/scsi/Kconfig ## diff --git a/debian/patches/features/ia64/rtc-efi.patch b/debian/patches/features/ia64/rtc-efi.patch new file mode 100644 index 000000000..6fd934a12 --- /dev/null +++ b/debian/patches/features/ia64/rtc-efi.patch @@ -0,0 +1,325 @@ +commit 5e3fd9e5810f141c9c70c36992d4ed72b3aa1fed +Author: dann frazier +Date: Tue Mar 31 15:24:48 2009 -0700 + + rtc: add platform driver for EFI + + Munge Stephane Eranian's efirtc.c code into an rtc platform driver + + [akpm@linux-foundation.org: use is_leap_year()] + Signed-off-by: dann frazier + Cc: Alessandro Zummo + Cc: stephane eranian + Cc: "Luck, Tony" + Cc: David Brownell + Signed-off-by: Andrew Morton + Signed-off-by: Linus Torvalds + +diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c +index f0ebb34..d6747ba 100644 +--- a/arch/ia64/kernel/time.c ++++ b/arch/ia64/kernel/time.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -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 81450fb..d669b91 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -440,6 +440,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 0e697aa..e7b0998 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -36,6 +36,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..5502923 +--- /dev/null ++++ b/drivers/rtc/rtc-efi.c +@@ -0,0 +1,235 @@ ++/* ++ * rtc-efi: RTC Class Driver for EFI-based systems ++ * ++ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. ++ * ++ * Author: dann frazier ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) ++/* ++ * EFI Epoch is 1/1/1998 ++ */ ++#define EFI_RTC_EPOCH 1998 ++ ++/* ++ * 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 + (is_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 "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("EFI RTC driver"); diff --git a/debian/patches/features/ia64/rtc-inline-LEAP_YEAR.patch b/debian/patches/features/ia64/rtc-inline-LEAP_YEAR.patch new file mode 100644 index 000000000..1fa0ed166 --- /dev/null +++ b/debian/patches/features/ia64/rtc-inline-LEAP_YEAR.patch @@ -0,0 +1,83 @@ +commit 78d89ef40c2ff7265df077e20c4d76be7d415204 +Author: Andrew Morton +Date: Tue Mar 31 15:24:48 2009 -0700 + + rtc: convert LEAP_YEAR into an inline + + - 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 + Acked-by: Alessandro Zummo + Cc: stephane eranian + Cc: "Luck, Tony" + Cc: David Brownell + Signed-off-by: Andrew Morton + Signed-off-by: Linus Torvalds + +diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c +index dd70bf7..773851f 100644 +--- a/drivers/rtc/rtc-lib.c ++++ b/drivers/rtc/rtc-lib.c +@@ -26,14 +26,13 @@ static const unsigned short rtc_ydays[2][13] = { + }; + + #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, struct rtc_time *tm) + - 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 --git a/include/linux/rtc.h b/include/linux/rtc.h +index 4046b75..60f88a7 100644 +--- a/include/linux/rtc.h ++++ b/include/linux/rtc.h +@@ -99,6 +99,7 @@ struct rtc_pll_info { + + #ifdef __KERNEL__ + ++#include + #include + + 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_ */ diff --git a/debian/patches/series/5 b/debian/patches/series/5 new file mode 100644 index 000000000..9c78db541 --- /dev/null +++ b/debian/patches/series/5 @@ -0,0 +1,2 @@ ++ features/ia64/rtc-efi.patch ++ features/ia64/rtc-inline-LEAP_YEAR.patch