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 bool convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime) { memset(wtime, 0, sizeof(*wtime)); if (eft->second >= 60) return false; wtime->tm_sec = eft->second; if (eft->minute >= 60) return false; wtime->tm_min = eft->minute; if (eft->hour >= 24) return false; wtime->tm_hour = eft->hour; if (!eft->day || eft->day > 31) return false; wtime->tm_mday = eft->day; if (!eft->month || eft->month > 12) return false; wtime->tm_mon = eft->month - 1; if (eft->year < 1900 || eft->year > 9999) return false; wtime->tm_year = eft->year - 1900; /* day in the year [1-365]*/ wtime->tm_yday = compute_yday(eft); /* day of the week [0-6], Sunday=0 */ wtime->tm_wday = compute_wday(eft, wtime->tm_yday); 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; } return true; }
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); return (ndays + 4) % 7; }
/* * 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) { pr_err("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; }
/* * Handle commands from user-space */ static int at91_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time tm, tm2; int ret = 0; spin_lock_irq(&at91_rtc_lock); switch (cmd) { case RTC_AIE_OFF: /* alarm off */ AT91_SYS->RTC_IDR = AT91C_RTC_ALARM; rtc_irq_data = 0; break; case RTC_AIE_ON: /* alarm on */ AT91_SYS->RTC_IER = AT91C_RTC_ALARM; rtc_irq_data = 0; break; case RTC_UIE_OFF: /* update off */ AT91_SYS->RTC_IDR = AT91C_RTC_SECEV; rtc_irq_data = 0; break; case RTC_UIE_ON: /* update on */ AT91_SYS->RTC_IER = AT91C_RTC_SECEV; rtc_irq_data = 0; break; case RTC_PIE_OFF: /* periodic off */ AT91_SYS->RTC_IDR = AT91C_RTC_SECEV; rtc_irq_data = 0; break; case RTC_PIE_ON: /* periodic on */ AT91_SYS->RTC_IER = AT91C_RTC_SECEV; rtc_irq_data = 0; break; case RTC_ALM_READ: /* read alarm */ at91_rtc_decodetime(&(AT91_SYS->RTC_TIMALR), &(AT91_SYS->RTC_CALALR), &tm); tm.tm_yday = compute_yday(tm.tm_year, tm.tm_mon, tm.tm_mday); tm.tm_year = at91_alarm_year - 1900; ret = copy_to_user((void *) arg, &tm, sizeof(tm)) ? -EFAULT : 0; break; case RTC_ALM_SET: /* set alarm */ if (copy_from_user(&tm2, (struct rtc_time *) arg, sizeof(tm2))) ret = -EFAULT; else { at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm); at91_alarm_year = tm.tm_year; if ((unsigned) tm2.tm_hour < 24) /* do some range checking */ tm.tm_hour = tm2.tm_hour; if ((unsigned) tm2.tm_min < 60) tm.tm_min = tm2.tm_min; if ((unsigned) tm2.tm_sec < 60) tm.tm_sec = tm2.tm_sec; AT91_SYS->RTC_TIMALR = BIN2BCD(tm.tm_sec) << 0 | BIN2BCD(tm.tm_min) << 8 | BIN2BCD(tm.tm_hour) << 16 | AT91C_RTC_HOUREN | AT91C_RTC_MINEN | AT91C_RTC_SECEN; AT91_SYS->RTC_CALALR = BIN2BCD(tm.tm_mon + 1) << 16 /* tm_mon starts at zero */ | BIN2BCD(tm.tm_mday) << 24 | AT91C_RTC_DATEEN | AT91C_RTC_MONTHEN; } break; case RTC_RD_TIME: /* read time */ at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm); tm.tm_yday = compute_yday(tm.tm_year, tm.tm_mon, tm.tm_mday); tm.tm_year = tm.tm_year - 1900; ret = copy_to_user((void *) arg, &tm, sizeof(tm)) ? -EFAULT : 0; break; case RTC_SET_TIME: /* set time */ if (!capable(CAP_SYS_TIME)) ret = -EACCES; else { if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(tm))) ret = -EFAULT; else { int tm_year = tm.tm_year + 1900; if (tm_year < EPOCH || (unsigned) tm.tm_mon >= 12 || tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] + (tm.tm_mon == 1 && is_leap(tm_year))) || (unsigned) tm.tm_hour >= 24 || (unsigned) tm.tm_min >= 60 || (unsigned) tm.tm_sec >= 60) ret = -EINVAL; else at91_rtc_settime(&tm); } } break; case RTC_IRQP_READ: /* read periodic alarm frequency */ ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg); break; case RTC_IRQP_SET: /* set periodic alarm frequency */ if (arg != AT91_RTC_FREQ) ret = -EINVAL; break; case RTC_EPOCH_READ: /* read epoch */ ret = put_user(EPOCH, (unsigned long *) arg); break; default: ret = -EINVAL; break; } spin_unlock_irq(&at91_rtc_lock); return ret; }