0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0012
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/stringify.h>
0016 #include <linux/time.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/rtc.h>
0019 #include <linux/efi.h>
0020
0021 #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
0022
0023
0024
0025
0026 static inline int
0027 compute_yday(efi_time_t *eft)
0028 {
0029
0030 return rtc_year_days(eft->day, eft->month - 1, eft->year);
0031 }
0032
0033
0034
0035
0036 static int
0037 compute_wday(efi_time_t *eft, int yday)
0038 {
0039 int ndays = eft->year * (365 % 7)
0040 + (eft->year - 1) / 4
0041 - (eft->year - 1) / 100
0042 + (eft->year - 1) / 400
0043 + yday;
0044
0045
0046
0047
0048
0049 return ndays % 7;
0050 }
0051
0052 static void
0053 convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
0054 {
0055 eft->year = wtime->tm_year + 1900;
0056 eft->month = wtime->tm_mon + 1;
0057 eft->day = wtime->tm_mday;
0058 eft->hour = wtime->tm_hour;
0059 eft->minute = wtime->tm_min;
0060 eft->second = wtime->tm_sec;
0061 eft->nanosecond = 0;
0062 eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
0063 eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
0064 }
0065
0066 static bool
0067 convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
0068 {
0069 memset(wtime, 0, sizeof(*wtime));
0070
0071 if (eft->second >= 60)
0072 return false;
0073 wtime->tm_sec = eft->second;
0074
0075 if (eft->minute >= 60)
0076 return false;
0077 wtime->tm_min = eft->minute;
0078
0079 if (eft->hour >= 24)
0080 return false;
0081 wtime->tm_hour = eft->hour;
0082
0083 if (!eft->day || eft->day > 31)
0084 return false;
0085 wtime->tm_mday = eft->day;
0086
0087 if (!eft->month || eft->month > 12)
0088 return false;
0089 wtime->tm_mon = eft->month - 1;
0090
0091 if (eft->year < 1900 || eft->year > 9999)
0092 return false;
0093 wtime->tm_year = eft->year - 1900;
0094
0095
0096 wtime->tm_yday = compute_yday(eft);
0097
0098
0099 wtime->tm_wday = compute_wday(eft, wtime->tm_yday);
0100
0101 switch (eft->daylight & EFI_ISDST) {
0102 case EFI_ISDST:
0103 wtime->tm_isdst = 1;
0104 break;
0105 case EFI_TIME_ADJUST_DAYLIGHT:
0106 wtime->tm_isdst = 0;
0107 break;
0108 default:
0109 wtime->tm_isdst = -1;
0110 }
0111
0112 return true;
0113 }
0114
0115 static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
0116 {
0117 efi_time_t eft;
0118 efi_status_t status;
0119
0120
0121
0122
0123 status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
0124 (efi_bool_t *)&wkalrm->pending, &eft);
0125
0126 if (status != EFI_SUCCESS)
0127 return -EINVAL;
0128
0129 if (!convert_from_efi_time(&eft, &wkalrm->time))
0130 return -EIO;
0131
0132 return rtc_valid_tm(&wkalrm->time);
0133 }
0134
0135 static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
0136 {
0137 efi_time_t eft;
0138 efi_status_t status;
0139
0140 convert_to_efi_time(&wkalrm->time, &eft);
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
0151
0152 dev_warn(dev, "write status is %d\n", (int)status);
0153
0154 return status == EFI_SUCCESS ? 0 : -EINVAL;
0155 }
0156
0157 static int efi_read_time(struct device *dev, struct rtc_time *tm)
0158 {
0159 efi_status_t status;
0160 efi_time_t eft;
0161 efi_time_cap_t cap;
0162
0163 status = efi.get_time(&eft, &cap);
0164
0165 if (status != EFI_SUCCESS) {
0166
0167 dev_err(dev, "can't read time\n");
0168 return -EINVAL;
0169 }
0170
0171 if (!convert_from_efi_time(&eft, tm))
0172 return -EIO;
0173
0174 return 0;
0175 }
0176
0177 static int efi_set_time(struct device *dev, struct rtc_time *tm)
0178 {
0179 efi_status_t status;
0180 efi_time_t eft;
0181
0182 convert_to_efi_time(tm, &eft);
0183
0184 status = efi.set_time(&eft);
0185
0186 return status == EFI_SUCCESS ? 0 : -EINVAL;
0187 }
0188
0189 static int efi_procfs(struct device *dev, struct seq_file *seq)
0190 {
0191 efi_time_t eft, alm;
0192 efi_time_cap_t cap;
0193 efi_bool_t enabled, pending;
0194
0195 memset(&eft, 0, sizeof(eft));
0196 memset(&alm, 0, sizeof(alm));
0197 memset(&cap, 0, sizeof(cap));
0198
0199 efi.get_time(&eft, &cap);
0200 efi.get_wakeup_time(&enabled, &pending, &alm);
0201
0202 seq_printf(seq,
0203 "Time\t\t: %u:%u:%u.%09u\n"
0204 "Date\t\t: %u-%u-%u\n"
0205 "Daylight\t: %u\n",
0206 eft.hour, eft.minute, eft.second, eft.nanosecond,
0207 eft.year, eft.month, eft.day,
0208 eft.daylight);
0209
0210 if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
0211 seq_puts(seq, "Timezone\t: unspecified\n");
0212 else
0213
0214 seq_printf(seq, "Timezone\t: %u\n", eft.timezone);
0215
0216 seq_printf(seq,
0217 "Alarm Time\t: %u:%u:%u.%09u\n"
0218 "Alarm Date\t: %u-%u-%u\n"
0219 "Alarm Daylight\t: %u\n"
0220 "Enabled\t\t: %s\n"
0221 "Pending\t\t: %s\n",
0222 alm.hour, alm.minute, alm.second, alm.nanosecond,
0223 alm.year, alm.month, alm.day,
0224 alm.daylight,
0225 enabled == 1 ? "yes" : "no",
0226 pending == 1 ? "yes" : "no");
0227
0228 if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
0229 seq_puts(seq, "Timezone\t: unspecified\n");
0230 else
0231
0232 seq_printf(seq, "Timezone\t: %u\n", alm.timezone);
0233
0234
0235
0236
0237 seq_printf(seq,
0238 "Resolution\t: %u\n"
0239 "Accuracy\t: %u\n"
0240 "SetstoZero\t: %u\n",
0241 cap.resolution, cap.accuracy, cap.sets_to_zero);
0242
0243 return 0;
0244 }
0245
0246 static const struct rtc_class_ops efi_rtc_ops = {
0247 .read_time = efi_read_time,
0248 .set_time = efi_set_time,
0249 .read_alarm = efi_read_alarm,
0250 .set_alarm = efi_set_alarm,
0251 .proc = efi_procfs,
0252 };
0253
0254 static int __init efi_rtc_probe(struct platform_device *dev)
0255 {
0256 struct rtc_device *rtc;
0257 efi_time_t eft;
0258 efi_time_cap_t cap;
0259
0260
0261 if (efi.get_time(&eft, &cap) != EFI_SUCCESS)
0262 return -ENODEV;
0263
0264 rtc = devm_rtc_allocate_device(&dev->dev);
0265 if (IS_ERR(rtc))
0266 return PTR_ERR(rtc);
0267
0268 platform_set_drvdata(dev, rtc);
0269
0270 rtc->ops = &efi_rtc_ops;
0271 clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
0272 set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features);
0273
0274 return devm_rtc_register_device(rtc);
0275 }
0276
0277 static struct platform_driver efi_rtc_driver = {
0278 .driver = {
0279 .name = "rtc-efi",
0280 },
0281 };
0282
0283 module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
0284
0285 MODULE_AUTHOR("dann frazier <dannf@dannf.org>");
0286 MODULE_LICENSE("GPL");
0287 MODULE_DESCRIPTION("EFI RTC driver");
0288 MODULE_ALIAS("platform:rtc-efi");