This source file includes following definitions.
- compute_yday
- compute_wday
- convert_to_efi_time
- convert_from_efi_time
- efi_read_alarm
- efi_set_alarm
- efi_read_time
- efi_set_time
- efi_procfs
- efi_rtc_probe
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12 
  13 #include <linux/kernel.h>
  14 #include <linux/module.h>
  15 #include <linux/stringify.h>
  16 #include <linux/time.h>
  17 #include <linux/platform_device.h>
  18 #include <linux/rtc.h>
  19 #include <linux/efi.h>
  20 
  21 #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
  22 
  23 
  24 
  25 
  26 static inline int
  27 compute_yday(efi_time_t *eft)
  28 {
  29         
  30         return rtc_year_days(eft->day, eft->month - 1, eft->year);
  31 }
  32 
  33 
  34 
  35 
  36 static int
  37 compute_wday(efi_time_t *eft, int yday)
  38 {
  39         int ndays = eft->year * (365 % 7)
  40                     + (eft->year - 1) / 4
  41                     - (eft->year - 1) / 100
  42                     + (eft->year - 1) / 400
  43                     + yday;
  44 
  45         
  46 
  47 
  48 
  49         return ndays % 7;
  50 }
  51 
  52 static void
  53 convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
  54 {
  55         eft->year       = wtime->tm_year + 1900;
  56         eft->month      = wtime->tm_mon + 1;
  57         eft->day        = wtime->tm_mday;
  58         eft->hour       = wtime->tm_hour;
  59         eft->minute     = wtime->tm_min;
  60         eft->second     = wtime->tm_sec;
  61         eft->nanosecond = 0;
  62         eft->daylight   = wtime->tm_isdst ? EFI_ISDST : 0;
  63         eft->timezone   = EFI_UNSPECIFIED_TIMEZONE;
  64 }
  65 
  66 static bool
  67 convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
  68 {
  69         memset(wtime, 0, sizeof(*wtime));
  70 
  71         if (eft->second >= 60)
  72                 return false;
  73         wtime->tm_sec  = eft->second;
  74 
  75         if (eft->minute >= 60)
  76                 return false;
  77         wtime->tm_min  = eft->minute;
  78 
  79         if (eft->hour >= 24)
  80                 return false;
  81         wtime->tm_hour = eft->hour;
  82 
  83         if (!eft->day || eft->day > 31)
  84                 return false;
  85         wtime->tm_mday = eft->day;
  86 
  87         if (!eft->month || eft->month > 12)
  88                 return false;
  89         wtime->tm_mon  = eft->month - 1;
  90 
  91         if (eft->year < 1900 || eft->year > 9999)
  92                 return false;
  93         wtime->tm_year = eft->year - 1900;
  94 
  95         
  96         wtime->tm_yday = compute_yday(eft);
  97 
  98         
  99         wtime->tm_wday = compute_wday(eft, wtime->tm_yday);
 100 
 101         switch (eft->daylight & EFI_ISDST) {
 102         case EFI_ISDST:
 103                 wtime->tm_isdst = 1;
 104                 break;
 105         case EFI_TIME_ADJUST_DAYLIGHT:
 106                 wtime->tm_isdst = 0;
 107                 break;
 108         default:
 109                 wtime->tm_isdst = -1;
 110         }
 111 
 112         return true;
 113 }
 114 
 115 static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 116 {
 117         efi_time_t eft;
 118         efi_status_t status;
 119 
 120         
 121 
 122 
 123         status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
 124                                      (efi_bool_t *)&wkalrm->pending, &eft);
 125 
 126         if (status != EFI_SUCCESS)
 127                 return -EINVAL;
 128 
 129         if (!convert_from_efi_time(&eft, &wkalrm->time))
 130                 return -EIO;
 131 
 132         return rtc_valid_tm(&wkalrm->time);
 133 }
 134 
 135 static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 136 {
 137         efi_time_t eft;
 138         efi_status_t status;
 139 
 140         convert_to_efi_time(&wkalrm->time, &eft);
 141 
 142         
 143 
 144 
 145 
 146 
 147 
 148 
 149 
 150         status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
 151 
 152         dev_warn(dev, "write status is %d\n", (int)status);
 153 
 154         return status == EFI_SUCCESS ? 0 : -EINVAL;
 155 }
 156 
 157 static int efi_read_time(struct device *dev, struct rtc_time *tm)
 158 {
 159         efi_status_t status;
 160         efi_time_t eft;
 161         efi_time_cap_t cap;
 162 
 163         status = efi.get_time(&eft, &cap);
 164 
 165         if (status != EFI_SUCCESS) {
 166                 
 167                 dev_err(dev, "can't read time\n");
 168                 return -EINVAL;
 169         }
 170 
 171         if (!convert_from_efi_time(&eft, tm))
 172                 return -EIO;
 173 
 174         return 0;
 175 }
 176 
 177 static int efi_set_time(struct device *dev, struct rtc_time *tm)
 178 {
 179         efi_status_t status;
 180         efi_time_t eft;
 181 
 182         convert_to_efi_time(tm, &eft);
 183 
 184         status = efi.set_time(&eft);
 185 
 186         return status == EFI_SUCCESS ? 0 : -EINVAL;
 187 }
 188 
 189 static int efi_procfs(struct device *dev, struct seq_file *seq)
 190 {
 191         efi_time_t      eft, alm;
 192         efi_time_cap_t  cap;
 193         efi_bool_t      enabled, pending;
 194 
 195         memset(&eft, 0, sizeof(eft));
 196         memset(&alm, 0, sizeof(alm));
 197         memset(&cap, 0, sizeof(cap));
 198 
 199         efi.get_time(&eft, &cap);
 200         efi.get_wakeup_time(&enabled, &pending, &alm);
 201 
 202         seq_printf(seq,
 203                    "Time\t\t: %u:%u:%u.%09u\n"
 204                    "Date\t\t: %u-%u-%u\n"
 205                    "Daylight\t: %u\n",
 206                    eft.hour, eft.minute, eft.second, eft.nanosecond,
 207                    eft.year, eft.month, eft.day,
 208                    eft.daylight);
 209 
 210         if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
 211                 seq_puts(seq, "Timezone\t: unspecified\n");
 212         else
 213                 
 214                 seq_printf(seq, "Timezone\t: %u\n", eft.timezone);
 215 
 216         seq_printf(seq,
 217                    "Alarm Time\t: %u:%u:%u.%09u\n"
 218                    "Alarm Date\t: %u-%u-%u\n"
 219                    "Alarm Daylight\t: %u\n"
 220                    "Enabled\t\t: %s\n"
 221                    "Pending\t\t: %s\n",
 222                    alm.hour, alm.minute, alm.second, alm.nanosecond,
 223                    alm.year, alm.month, alm.day,
 224                    alm.daylight,
 225                    enabled == 1 ? "yes" : "no",
 226                    pending == 1 ? "yes" : "no");
 227 
 228         if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
 229                 seq_puts(seq, "Timezone\t: unspecified\n");
 230         else
 231                 
 232                 seq_printf(seq, "Timezone\t: %u\n", alm.timezone);
 233 
 234         
 235 
 236 
 237         seq_printf(seq,
 238                    "Resolution\t: %u\n"
 239                    "Accuracy\t: %u\n"
 240                    "SetstoZero\t: %u\n",
 241                    cap.resolution, cap.accuracy, cap.sets_to_zero);
 242 
 243         return 0;
 244 }
 245 
 246 static const struct rtc_class_ops efi_rtc_ops = {
 247         .read_time      = efi_read_time,
 248         .set_time       = efi_set_time,
 249         .read_alarm     = efi_read_alarm,
 250         .set_alarm      = efi_set_alarm,
 251         .proc           = efi_procfs,
 252 };
 253 
 254 static int __init efi_rtc_probe(struct platform_device *dev)
 255 {
 256         struct rtc_device *rtc;
 257         efi_time_t eft;
 258         efi_time_cap_t cap;
 259 
 260         
 261         if (efi.get_time(&eft, &cap) != EFI_SUCCESS)
 262                 return -ENODEV;
 263 
 264         rtc = devm_rtc_device_register(&dev->dev, "rtc-efi", &efi_rtc_ops,
 265                                         THIS_MODULE);
 266         if (IS_ERR(rtc))
 267                 return PTR_ERR(rtc);
 268 
 269         rtc->uie_unsupported = 1;
 270         platform_set_drvdata(dev, rtc);
 271 
 272         return 0;
 273 }
 274 
 275 static struct platform_driver efi_rtc_driver = {
 276         .driver = {
 277                 .name = "rtc-efi",
 278         },
 279 };
 280 
 281 module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
 282 
 283 MODULE_ALIAS("platform:rtc-efi");
 284 MODULE_AUTHOR("dann frazier <dannf@dannf.org>");
 285 MODULE_LICENSE("GPL");
 286 MODULE_DESCRIPTION("EFI RTC driver");
 287 MODULE_ALIAS("platform:rtc-efi");