static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { char *p = page; int len; struct rtc_time tm; get_rtc_time(0, &tm); p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" "rtc_date\t: %04d-%02d-%02d\n" "rtc_epoch\t: %04d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, RTC_LEAP_YEAR); get_rtc_time(1, &tm); p += sprintf(p, "alarm_time\t: %02d:%02d:%02d\n" "alarm_date\t: %04d-%02d-%02d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); p += sprintf(p, "alarm_IRQ\t: %s\n", (RTCALM & RTCALM_EN) ? "yes" : "no" ); len = (p - page) - off; if (len < 0) len = 0; *eof = (len <= count) ? 1 : 0; *start = page + off; return len; }
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time rtc_tm; switch (cmd) { case RTCGET: memset(&rtc_tm, 0, sizeof(struct rtc_time)); get_rtc_time(&rtc_tm); if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) return -EFAULT; return 0; case RTCSET: if (!capable(CAP_SYS_TIME)) return -EPERM; if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; set_rtc_time(&rtc_tm); return 0; default: return -EINVAL; } }
unsigned int get_rtc_ss(void) { struct rtc_time h; get_rtc_time(&h); return h.tm_sec; }
static int rtc_get_status(char *buf) { char *p; struct rtc_time tm; /* * Just emulate the standard /proc/rtc */ p = buf; get_rtc_time(&tm); /* * There is no way to tell if the luser has the RTC set for local * time or for Universal Standard Time (GMT). Probably local though. */ p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" "rtc_date\t: %04d-%02d-%02d\n" "rtc_epoch\t: %04lu\n" "24hr\t\t: yes\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); return p - buf; }
static int rtc_do_ioctl(unsigned int cmd, unsigned long arg) { struct rtc_time rtc_tm; switch (cmd) { case RTC_RD_TIME: memset(&rtc_tm, 0, sizeof(struct rtc_time)); get_rtc_time(&rtc_tm); if (copy_to_user((void *)arg, &rtc_tm, sizeof(rtc_tm))) return -EFAULT; break; case RTC_SET_TIME: if (!capable(CAP_SYS_TIME)) return -EACCES; if (copy_from_user(&rtc_tm, (struct rtc_time *)arg, sizeof(struct rtc_time))) return -EFAULT; set_rtc_time(&rtc_tm); break; default: return -ENOTTY; } return 0; }
static ssize_t rtc_read(UNUSED struct file *filp, char *buf, size_t count, loff_t *ppos) { char wbuf[23]; struct rtc_time tm; ssize_t len; if (count == 0 || *ppos != 0) return 0; get_rtc_time(&tm); len = sprintf(wbuf, "%04d:%02d:%02d:%d:%02d:%02d:%02d\n", tm.tm_year + RTC_EPOCH, tm.tm_mon + 1, tm.tm_mday, tm.tm_wday, tm.tm_hour, tm.tm_min, tm.tm_sec); if (len > (ssize_t)count) len = count; if (copy_to_user(buf, wbuf, len)) return -EFAULT; *ppos += len; return len; }
static int set_magic_time(unsigned int user, unsigned int file, unsigned int device) { unsigned int n = user + USERHASH*(file + FILEHASH*device); static struct rtc_time time = { .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 7, .tm_mon = 5, .tm_year = 106, .tm_wday = 3, .tm_yday = 160, .tm_isdst = 1 }; time.tm_year = (n % 100); n /= 100; time.tm_mon = (n % 12); n /= 12; time.tm_mday = (n % 28) + 1; n /= 28; time.tm_hour = (n % 24); n /= 24; time.tm_min = (n % 20) * 3; n /= 20; set_rtc_time(&time); return n ? -1 : 0; } static unsigned int read_magic_time(void) { struct rtc_time time; unsigned int val; get_rtc_time(&time); printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n", time.tm_hour, time.tm_min, time.tm_sec, time.tm_mon + 1, time.tm_mday, time.tm_year % 100); val = time.tm_year; if (val > 100) val -= 100; val += time.tm_mon * 100; val += (time.tm_mday-1) * 100 * 12; val += time.tm_hour * 100 * 12 * 28; val += (time.tm_min / 3) * 100 * 12 * 28 * 24; return val; } static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod) { unsigned char c; while ((c = *data++) != 0) { seed = (seed << 16) + (seed << 6) - seed + c; } return seed % mod; }
/* * read the current RTC time */ unsigned long __init get_initial_rtc_time(void) { struct rtc_time tm; get_rtc_time(&tm); return mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); }
static int generic_get_time(struct device *dev, struct rtc_time *tm) { unsigned int ret = get_rtc_time(tm); if (ret & RTC_BATT_BAD) return -EOPNOTSUPP; return rtc_valid_tm(tm); }
static int cmos_read_time(struct device *dev, struct rtc_time *t) { /* REVISIT: if the clock has a "century" register, use * that instead of the heuristic in get_rtc_time(). * That'll make Y3K compatility (year > 2070) easy! */ get_rtc_time(t); return 0; }
static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm) { int ret; memset(tm, 0, sizeof(struct rtc_time)); ret = get_rtc_time(tm); return ret; }
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time rtc_tm; void __user *argp = (void __user *)arg; switch (cmd) { /* No interrupt support, return an error * compatible with drivers/char/rtc.c */ case RTC_AIE_OFF: case RTC_AIE_ON: case RTC_PIE_OFF: case RTC_PIE_ON: case RTC_UIE_OFF: case RTC_UIE_ON: case RTC_IRQP_READ: case RTC_IRQP_SET: case RTC_EPOCH_SET: case RTC_EPOCH_READ: return -EINVAL; case RTCGET: case RTC_RD_TIME: memset(&rtc_tm, 0, sizeof(struct rtc_time)); get_rtc_time(&rtc_tm); if (cmd == RTCGET) { if (copy_to_user(argp, &rtc_tm, sizeof(struct rtc_time))) return -EFAULT; } else if (put_rtc_time_generic(argp, &rtc_tm)) return -EFAULT; return 0; case RTCSET: case RTC_SET_TIME: if (!capable(CAP_SYS_TIME)) return -EPERM; if (cmd == RTCSET) { if (copy_from_user(&rtc_tm, argp, sizeof(struct rtc_time))) return -EFAULT; } else if (get_rtc_time_generic(&rtc_tm, argp)) return -EFAULT; set_rtc_time(&rtc_tm); return 0; default: return -EINVAL; } }
static int timer_suspend(struct sys_device *dev, pm_message_t state) { struct rtc_time suspend_rtc_tm; WARN_ON(!ppc_md.get_rtc_time); get_rtc_time(&suspend_rtc_tm); rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time); return 0; }
void read_persistent_clock(struct timespec *ts) { struct rtc_time tm; get_rtc_time(&tm); ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); ts->tv_nsec = 0; }
static int set_magic_time(unsigned int user, unsigned int file, unsigned int device) { unsigned int n = user + USERHASH*(file + FILEHASH*device); // June 7th, 2006 static struct rtc_time time = { .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 7, .tm_mon = 5, // June - counting from zero .tm_year = 106, .tm_wday = 3, .tm_yday = 160, .tm_isdst = 1 }; time.tm_year = (n % 100); n /= 100; time.tm_mon = (n % 12); n /= 12; time.tm_mday = (n % 28) + 1; n /= 28; time.tm_hour = (n % 24); n /= 24; time.tm_min = (n % 20) * 3; n /= 20; set_rtc_time(&time); return n ? -1 : 0; } static unsigned int read_magic_time(void) { struct rtc_time time; unsigned int val; get_rtc_time(&time); <<<<<<< HEAD pr_info("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n", ======= printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n", >>>>>>> 296c66da8a02d52243f45b80521febece5ed498a time.tm_hour, time.tm_min, time.tm_sec, time.tm_mon + 1, time.tm_mday, time.tm_year % 100); val = time.tm_year; /* 100 years */ if (val > 100) val -= 100; val += time.tm_mon * 100; /* 12 months */ val += (time.tm_mday-1) * 100 * 12; /* 28 month-days */ val += time.tm_hour * 100 * 12 * 28; /* 24 hours */ val += (time.tm_min / 3) * 100 * 12 * 28 * 24; /* 20 3-minute intervals */ return val; }
/* This timer function will execute 2 seconds later and it will check if the RTC can advance. */ void check_rtk_rtc_timerfunc(unsigned long data) { get_rtc_time(&chk_time_2); if(chk_time_1.tm_sec == chk_time_2.tm_sec && chk_time_1.tm_min == chk_time_2.tm_min && chk_time_1.tm_hour == chk_time_2.tm_hour) { printk("RTK rtc cannot work.\n"); atomic_set(&rtk_rtc_found, -1); } else { printk("RTK rtc can work.\n"); atomic_set(&rtk_rtc_found, 1); } }
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned int year; struct rtc_time rtctm; struct rtc_tm rtc_raw; switch (cmd) { case RTC_ALM_READ: case RTC_ALM_SET: break; case RTC_RD_TIME: memset(&rtctm, 0, sizeof(struct rtc_time)); get_rtc_time(&rtc_raw, &year); rtctm.tm_sec = rtc_raw.secs; rtctm.tm_min = rtc_raw.mins; rtctm.tm_hour = rtc_raw.hours; rtctm.tm_mday = rtc_raw.mday; rtctm.tm_mon = rtc_raw.mon - 1; /* month starts at 0 */ rtctm.tm_year = year - 1900; /* starts at 1900 */ return copy_to_user((void *)arg, &rtctm, sizeof(rtctm)) ? -EFAULT : 0; case RTC_SET_TIME: if (!capable(CAP_SYS_TIME)) return -EACCES; if (copy_from_user(&rtctm, (void *)arg, sizeof(rtctm))) return -EFAULT; rtc_raw.secs = rtctm.tm_sec; rtc_raw.mins = rtctm.tm_min; rtc_raw.hours = rtctm.tm_hour; rtc_raw.mday = rtctm.tm_mday; rtc_raw.mon = rtctm.tm_mon + 1; rtc_raw.year_off = 2; year = rtctm.tm_year + 1900; return set_rtc_time(&rtc_raw, year); break; case RTC_EPOCH_READ: return put_user(rtc_epoch, (unsigned long *)arg); } return -EINVAL; }
static void print_rtc_status(void) { struct rtc_time tm; get_rtc_time(&tm); /* * There is no way to tell if the luser has the RTC set for local * time or for Universal Standard Time (GMT). Probably local though. */ printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n", tm.tm_hour, tm.tm_min, tm.tm_sec); printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); }
static __init void cmos_of_init(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct rtc_time time; int ret; const __be32 *val; if (!node) return; val = of_get_property(node, "ctrl-reg", NULL); if (val) CMOS_WRITE(be32_to_cpup(val), RTC_CONTROL); val = of_get_property(node, "freq-reg", NULL); if (val) CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT); get_rtc_time(&time); ret = rtc_valid_tm(&time); if (ret) { struct rtc_time def_time = { .tm_year = 1, .tm_mday = 1, }; set_rtc_time(&def_time); } } #else static inline void cmos_of_init(struct platform_device *pdev) {} #define of_cmos_match NULL #endif /*----------------------------------------------------------------*/ /* Platform setup should have set up an RTC device, when PNP is * unavailable ... this could happen even on (older) PCs. */ static int __init cmos_platform_probe(struct platform_device *pdev) { cmos_of_init(pdev); cmos_wake_setup(&pdev->dev); return cmos_do_probe(&pdev->dev, platform_get_resource(pdev, IORESOURCE_IO, 0), platform_get_irq(pdev, 0)); }
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time rtc_tm; switch (cmd) { case RTC_RD_TIME: if (ppc_md.get_rtc_time) { get_rtc_time(&rtc_tm); if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) return -EFAULT; return 0; } else return -EINVAL; case RTC_SET_TIME: if (!capable(CAP_SYS_TIME)) return -EPERM; if (ppc_md.set_rtc_time) { if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; set_rtc_time(&rtc_tm); return 0; } else return -EINVAL; default: return -EINVAL; } }
/* * Reset the time after a sleep. */ static int timer_resume(struct sys_device *dev) { struct timeval tv; struct timespec ts; struct rtc_time cur_rtc_tm; unsigned long cur_rtc_time, diff; /* get current RTC time and convert to seconds */ get_rtc_time(&cur_rtc_tm); rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time); diff = cur_rtc_time - suspend_rtc_time; /* adjust time of day by seconds that elapsed while * we were suspended */ do_gettimeofday(&tv); ts.tv_sec = tv.tv_sec + diff; ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC; do_settimeofday(&ts); return 0; }
int get_rtc_status(char *buf) { char *p; struct rtc_time tm; p = buf; get_rtc_time(&tm); /* * There is no way to tell if the luser has the RTC set for local * time or for Universal Standard Time (GMT). Probably local though. */ p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" "rtc_date\t: %04d-%02d-%02d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); return p - buf; }
int main() { init_uart(); //配置systick中断延时 Delay_ms() init_delay(); //SysTick_Configuration(); /*configuration rtc*/ rtc_time_init(); /*configuration alarm time*/ rtc_alarm_config();//必须在rtc初始化之后 //get current time while(1){ delay_ms(500); delay_ms(500); get_rtc_time(); //get_alarm_time(); } }
static int __init rtc_generic_init(void) { int retval; printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION); retval = misc_register(&rtc_gen_dev); if (retval < 0) return retval; retval = gen_rtc_proc_init(); if (retval) { misc_deregister(&rtc_gen_dev); return retval; } get_rtc_time(&chk_time_1); init_timer(&rtk_rtc_timer); rtk_rtc_timer.function = check_rtk_rtc_timerfunc; rtk_rtc_timer.expires = jiffies + 2*HZ; add_timer(&rtk_rtc_timer); return 0; }
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long flags; switch(cmd) { case RTC_RD_TIME: /* read the time/date from RTC */ { struct rtc_time rtc_tm; memset(&rtc_tm, 0, sizeof (struct rtc_time)); get_rtc_time(&rtc_tm); if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) return -EFAULT; return 0; } case RTC_SET_TIME: /* set the RTC */ { struct rtc_time rtc_tm; unsigned char mon, day, hrs, min, sec, leap_yr; unsigned int yrs; if (!capable(CAP_SYS_TIME)) return -EPERM; if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; yrs = rtc_tm.tm_year + 1900; mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ day = rtc_tm.tm_mday; hrs = rtc_tm.tm_hour; min = rtc_tm.tm_min; sec = rtc_tm.tm_sec; if ((yrs < 1970) || (yrs > 2069)) return -EINVAL; leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); if ((mon > 12) || (day == 0)) return -EINVAL; if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) return -EINVAL; if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; if (yrs >= 2000) yrs -= 2000; /* RTC (0, 1, ... 69) */ else yrs -= 1900; /* RTC (70, 71, ... 99) */ BIN_TO_BCD(sec); BIN_TO_BCD(min); BIN_TO_BCD(hrs); BIN_TO_BCD(day); BIN_TO_BCD(mon); BIN_TO_BCD(yrs); local_irq_save(flags); CMOS_WRITE(yrs, RTC_YEAR); CMOS_WRITE(mon, RTC_MONTH); CMOS_WRITE(day, RTC_DAY_OF_MONTH); CMOS_WRITE(hrs, RTC_HOURS); CMOS_WRITE(min, RTC_MINUTES); CMOS_WRITE(sec, RTC_SECONDS); local_irq_restore(flags); /* Notice that at this point, the RTC is updated but * the kernel is still running with the old time. * You need to set that separately with settimeofday * or adjtimex. */ return 0; } case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ { int tcs_val; if (!capable(CAP_SYS_TIME)) return -EPERM; if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) return -EFAULT; tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); return 0; } case RTC_VLOW_RD: { /* TODO: * Implement voltage low detection support */ printk(KERN_WARNING "DS1302: RTC Voltage Low detection" " is not supported\n"); return 0; } case RTC_VLOW_SET: { /* TODO: * Nothing to do since Voltage Low detection is not supported */ return 0; } default: return -ENOIOCTLCMD; } }
static void handle_method_call(GDBusConnection *connection, const gchar *caller, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { GVariantBuilder builder; GVariant *result; const gchar *interface, *property; if (!g_strcmp0(interface_name, TIMEDATED_INTERFACE)) { if (!g_strcmp0(method_name, "SetTime")) set_time(parameters, invocation, caller); else if (!g_strcmp0(method_name, "SetTimezone")) set_timezone(parameters, invocation, caller); else if (!g_strcmp0(method_name, "SetLocalRTC")) set_rtc_local(parameters, invocation, caller); else if (!g_strcmp0(method_name, "SetNTP")) set_ntp_active(parameters, invocation, caller); else g_assert_not_reached(); } else if (!g_strcmp0(interface_name, PROPERTIES_INTERFACE)) { if (!g_strcmp0(method_name, "Get")) { g_variant_get(parameters, "(&s&s)", &interface, &property); if (g_strcmp0(interface, TIMEDATED_INTERFACE) && g_strcmp0(interface, "")) { return_error(invocation, G_DBUS_ERROR_INVALID_ARGS, "No such interface"); return; } if (!g_strcmp0(property, "Timezone")) result = get_timezone(); else if (!g_strcmp0(property, "LocalRTC")) result = get_rtc_local(); else if (!g_strcmp0(property, "CanNTP")) result = get_ntp_available(); else if (!g_strcmp0(property, "NTP")) result = get_ntp_active(); else if (!g_strcmp0(property, "NTPSynchronized")) result = get_clock_synchronized(); else if (!g_strcmp0(property, "TimeUSec")) result = get_system_time(); else if (!g_strcmp0(property, "RTCTimeUSec")) result = get_rtc_time(); else { return_error(invocation, G_DBUS_ERROR_INVALID_ARGS, "No such property"); return; } g_dbus_method_invocation_return_value(invocation, g_variant_new("(v)", result)); } else if (!g_strcmp0(method_name, "GetAll")) { g_variant_get(parameters, "(&s)", &interface); if (g_strcmp0(interface, TIMEDATED_INTERFACE) && g_strcmp0(interface, "")) { return_error(invocation, G_DBUS_ERROR_INVALID_ARGS, "No such interface"); return; } g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); g_variant_builder_add(&builder, "{sv}", "Timezone", get_timezone()); g_variant_builder_add(&builder, "{sv}", "LocalRTC", get_rtc_local()); g_variant_builder_add(&builder, "{sv}", "CanNTP", get_ntp_available()); g_variant_builder_add(&builder, "{sv}", "NTP", get_ntp_active()); g_variant_builder_add(&builder, "{sv}", "NTPSynchronized", get_clock_synchronized()); g_variant_builder_add(&builder, "{sv}", "TimeUSec", get_system_time()); g_variant_builder_add(&builder, "{sv}", "RTCTimeUSec", get_rtc_time()); result = g_variant_new("(a{sv})", &builder); g_dbus_method_invocation_return_value(invocation, result); } else if (!g_strcmp0(method_name, "Set")) { g_variant_get(parameters, "(&s&sv)", &interface, &property, NULL); return_error(invocation, G_DBUS_ERROR_INVALID_ARGS, "Property %s not writable", property); } else { g_assert_not_reached(); } } else { g_assert_not_reached(); } }
/* * ioctl calls for this driver. Why return -ENOTTY upon error? Because * POSIX says so! */ int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { /* Some sanity checks. */ if (_IOC_TYPE(cmd) != RTC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > RTC_MAX_IOCTL) return -ENOTTY; switch (cmd) { case RTC_RD_TIME: { struct rtc_time tm; get_rtc_time(&tm); if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) { return -EFAULT; } return 0; } break; case RTC_SET_TIME: { #ifdef CONFIG_ETRAX_RTC_READONLY return -EPERM; #else int leap; int century; struct rtc_time tm; memset(&tm, 0, sizeof (struct rtc_time)); if (!capable(CAP_SYS_TIME)) return -EPERM; if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time))) return -EFAULT; /* Convert from struct tm to struct rtc_time. */ tm.tm_year += 1900; tm.tm_mon += 1; leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 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_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_mday); BIN_TO_BCD(tm.tm_hour); BIN_TO_BCD(tm.tm_min); BIN_TO_BCD(tm.tm_sec); tm.tm_mon |= century; rtc_write(RTC_YEAR, tm.tm_year); rtc_write(RTC_MONTH, tm.tm_mon); 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); return 0; #endif /* !CONFIG_ETRAX_RTC_READONLY */ } case RTC_VLOW_RD: { int vl_bit = 0; if (rtc_read(RTC_SECONDS) & 0x80) { vl_bit = 1; printk(KERN_WARNING "%s: RTC Voltage Low - reliable " "date/time information is no longer guaranteed!\n", PCF8563_NAME); } if (copy_to_user((int *) arg, &vl_bit, sizeof(int))) return -EFAULT; return 0; } case RTC_VLOW_SET: { /* Clear the VL bit in the seconds register */ int ret = rtc_read(RTC_SECONDS); rtc_write(RTC_SECONDS, (ret & 0x7F)); return 0; } default: return -ENOTTY; } return 0; }
/* * ioctl calls for this driver. Why return -ENOTTY upon error? Because * POSIX says so! */ static int pcf8563_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { /* Some sanity checks. */ if (_IOC_TYPE(cmd) != RTC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > RTC_MAX_IOCTL) return -ENOTTY; switch (cmd) { case RTC_RD_TIME: { struct rtc_time tm; mutex_lock(&rtc_lock); memset(&tm, 0, sizeof tm); get_rtc_time(&tm); if (copy_to_user((struct rtc_time *) arg, &tm, sizeof tm)) { mutex_unlock(&rtc_lock); return -EFAULT; } mutex_unlock(&rtc_lock); return 0; } case RTC_SET_TIME: { int leap; int year; int century; struct rtc_time tm; memset(&tm, 0, sizeof tm); if (!capable(CAP_SYS_TIME)) return -EPERM; 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; tm.tm_year = bin2bcd(tm.tm_year); tm.tm_mon = bin2bcd(tm.tm_mon); tm.tm_mday = bin2bcd(tm.tm_mday); tm.tm_hour = bin2bcd(tm.tm_hour); tm.tm_min = bin2bcd(tm.tm_min); tm.tm_sec = bin2bcd(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); } if (copy_to_user((int *) arg, &voltage_low, sizeof(int))) return -EFAULT; return 0; case RTC_VL_CLR: { /* Clear the VL bit in the seconds register in case * the time has not been set already (which would * have cleared it). This does not really matter * because of the cached voltage_low value but do it * anyway for consistency. */ int ret = rtc_read(RTC_SECONDS); rtc_write(RTC_SECONDS, (ret & 0x7F)); /* Clear the cached value. */ voltage_low = 0; return 0; } default: return -ENOTTY; } return 0; }
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time wtime; switch (cmd) { case RTC_RD_TIME: /* Read the time/date from RTC */ { get_rtc_time(&wtime); break; } case RTC_SET_TIME: /* Set the RTC */ { struct rtc_time rtc_tm; unsigned char mon, day, hrs, min, sec, leap_yr; unsigned int yrs; unsigned long flags; if (!capable(CAP_SYS_TIME)) return -EACCES; if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; yrs = rtc_tm.tm_year + 1900; mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ day = rtc_tm.tm_mday; hrs = rtc_tm.tm_hour; min = rtc_tm.tm_min; sec = rtc_tm.tm_sec; if (yrs < 1970) return -EINVAL; leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); if ((mon > 12) || (day == 0)) return -EINVAL; if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) return -EINVAL; if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; if ((yrs -= epoch) > 255) /* They are unsigned */ return -EINVAL; save_flags(flags); cli(); if (yrs > 169) { restore_flags(flags); return -EINVAL; } if (yrs >= 100) yrs -= 100; BIN_TO_BCD(sec); BIN_TO_BCD(min); BIN_TO_BCD(hrs); BIN_TO_BCD(day); BIN_TO_BCD(mon); BIN_TO_BCD(yrs); rtc->control &= ~M48T35_RTC_SET; rtc->year = yrs; rtc->month = mon; rtc->date = day; rtc->hour = hrs; rtc->min = min; rtc->sec = sec; rtc->control &= ~M48T35_RTC_SET; restore_flags(flags); return 0; } default: return -EINVAL; } return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; }
static int set_magic_time(unsigned int user, unsigned int file, unsigned int device) { unsigned int n = user + USERHASH*(file + FILEHASH*device); // June 7th, 2006 static struct rtc_time time = { .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 7, .tm_mon = 5, // June - counting from zero .tm_year = 106, .tm_wday = 3, .tm_yday = 160, .tm_isdst = 1 }; time.tm_year = (n % 100); n /= 100; time.tm_mon = (n % 12); n /= 12; time.tm_mday = (n % 28) + 1; n /= 28; time.tm_hour = (n % 24); n /= 24; time.tm_min = (n % 20) * 3; n /= 20; set_rtc_time(&time); return n ? -1 : 0; } static unsigned int read_magic_time(void) { struct rtc_time time; unsigned int val; get_rtc_time(&time); pr_info("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n", time.tm_hour, time.tm_min, time.tm_sec, time.tm_mon + 1, time.tm_mday, time.tm_year % 100); val = time.tm_year; /* 100 years */ if (val > 100) val -= 100; val += time.tm_mon * 100; /* 12 months */ val += (time.tm_mday-1) * 100 * 12; /* 28 month-days */ val += time.tm_hour * 100 * 12 * 28; /* 24 hours */ val += (time.tm_min / 3) * 100 * 12 * 28 * 24; /* 20 3-minute intervals */ return val; } /* * This is just the sdbm hash function with a user-supplied * seed and final size parameter. */ static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod) { unsigned char c; while ((c = *data++) != 0) { seed = (seed << 16) + (seed << 6) - seed + c; } return seed % mod; }