+ if (copy_from_user(&tm, (struct rtc_time *) arg,
+ sizeof tm))
+ return -EFAULT;
+
+ /* Convert from struct tm to struct rtc_time. */
+ tm.tm_year += 1900;
+ tm.tm_mon += 1;
+
+ /*
+ * Check if tm.tm_year is a leap year. A year is a leap
+ * year if it is divisible by 4 but not 100, except
+ * that years divisible by 400 _are_ leap years.
+ */
+ year = tm.tm_year;
+ leap = (tm.tm_mon == 2) &&
+ ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
+
+ /* Perform some sanity checks. */
+ if ((tm.tm_year < 1970) ||
+ (tm.tm_mon > 12) ||
+ (tm.tm_mday == 0) ||
+ (tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
+ (tm.tm_wday >= 7) ||
+ (tm.tm_hour >= 24) ||
+ (tm.tm_min >= 60) ||
+ (tm.tm_sec >= 60))
+ return -EINVAL;
+
+ century = (tm.tm_year >= 2000) ? 0x80 : 0;
+ tm.tm_year = tm.tm_year % 100;
+
+ BIN_TO_BCD(tm.tm_year);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_sec);
+ tm.tm_mon |= century;
+
+ mutex_lock(&rtc_lock);
+
+ rtc_write(RTC_YEAR, tm.tm_year);
+ rtc_write(RTC_MONTH, tm.tm_mon);
+ rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */
+ rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
+ rtc_write(RTC_HOURS, tm.tm_hour);
+ rtc_write(RTC_MINUTES, tm.tm_min);
+ rtc_write(RTC_SECONDS, tm.tm_sec);
+
+ mutex_unlock(&rtc_lock);
+
+ return 0;
+ }
+ case RTC_VL_READ:
+ if (voltage_low)
+ printk(KERN_ERR "%s: RTC Voltage Low - "
+ "reliable date/time information is no "
+ "longer guaranteed!\n", PCF8563_NAME);