static int rtc_suspend(struct device *dev, pm_message_t mesg) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; struct timespec delta, delta_delta; if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; /* snapshot the current RTC and system time at suspend*/ rtc_read_time(rtc, &tm); getnstimeofday(&old_system); rtc_tm_to_time(&tm, &old_rtc.tv_sec); /* * To avoid drift caused by repeated suspend/resumes, * which each can add ~1 second drift error, * try to compensate so the difference in system time * and rtc time stays close to constant. */ delta = timespec_sub(old_system, old_rtc); delta_delta = timespec_sub(delta, old_delta); if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) { /* * if delta_delta is too large, assume time correction * has occured and set old_delta to the current delta. */ old_delta = delta; } else { /* Otherwise try to adjust old_system to compensate */ old_system = timespec_sub(old_system, delta_delta); } return 0; }
static int alarmtimer_rtc_add_device(struct device *dev, struct class_interface *class_intf) { unsigned long flags; struct rtc_device *rtc = to_rtc_device(dev); if (rtcdev) return -EBUSY; if (!rtc->ops->set_alarm) return -1; // printk("can_wakeup=%d, wakeup=%d\n",rtc->dev.parent->power.can_wakeup, rtc->dev.parent->power.wakeup); // printk("111\n"); // if (!device_may_wakeup(rtc->dev.parent)) // return -1; // printk("222\n"); spin_lock_irqsave(&rtcdev_lock, flags); if (!rtcdev) { rtcdev = rtc; /* hold a reference so it doesn't go away */ get_device(dev); } spin_unlock_irqrestore(&rtcdev_lock, flags); return 0; }
static int rtc_proc_add_device(struct class_device *class_dev, struct class_interface *class_intf) { mutex_lock(&rtc_lock); if (rtc_dev == NULL) { struct proc_dir_entry *ent; rtc_dev = class_dev; ent = create_proc_entry("driver/rtc", 0, NULL); if (ent) { struct rtc_device *rtc = to_rtc_device(class_dev); ent->proc_fops = &rtc_proc_fops; ent->owner = rtc->owner; ent->data = class_dev; dev_dbg(class_dev->dev, "rtc intf: proc\n"); } else rtc_dev = NULL; } mutex_unlock(&rtc_lock); return 0; }
static int alarmtimer_rtc_add_device(struct device *dev, struct class_interface *class_intf) { unsigned long flags; int err = 0; struct rtc_device *rtc = to_rtc_device(dev); if (rtcdev) return -EBUSY; if (!rtc->ops->set_alarm) return -1; spin_lock_irqsave(&rtcdev_lock, flags); if (!rtcdev) { err = rtc_irq_register(rtc, &alarmtimer_rtc_task); if (err) goto rtc_irq_reg_err; rtcdev = rtc; /* hold a reference so it doesn't go away */ get_device(dev); } rtc_irq_reg_err: spin_unlock_irqrestore(&rtcdev_lock, flags); return err; }
static ssize_t rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; unsigned long alarm; struct rtc_wkalrm alm; printk("%s \n", __func__); /* Don't show disabled alarms. For uniformity, RTC alarms are * conceptually one-shot, even though some common RTCs (on PCs) * don't actually work that way. * * NOTE: RTC implementations where the alarm doesn't match an * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC * alarms after they trigger, to ensure one-shot semantics. */ alm.enabled=1; retval = rtc_read_alarm(to_rtc_device(dev), &alm); printk("show_alarm retval: %d\n",retval); if (retval == 0 && alm.enabled) { rtc_tm_to_time(&alm.time, &alarm); retval = sprintf(buf, "%lu \n", alarm); printk("alarm buf: %s \n",buf); } return retval; }
static int rtc_proc_show(struct seq_file *seq, void *offset) { int err; struct class_device *class_dev = seq->private; const struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops; struct rtc_wkalrm alrm; struct rtc_time tm; err = rtc_read_time(class_dev, &tm); if (err == 0) { seq_printf(seq, "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); } err = rtc_read_alarm(class_dev, &alrm); if (err == 0) { seq_printf(seq, "alrm_time\t: "); if ((unsigned int)alrm.time.tm_hour <= 24) seq_printf(seq, "%02d:", alrm.time.tm_hour); else seq_printf(seq, "**:"); if ((unsigned int)alrm.time.tm_min <= 59) seq_printf(seq, "%02d:", alrm.time.tm_min); else seq_printf(seq, "**:"); if ((unsigned int)alrm.time.tm_sec <= 59) seq_printf(seq, "%02d\n", alrm.time.tm_sec); else seq_printf(seq, "**\n"); seq_printf(seq, "alrm_date\t: "); if ((unsigned int)alrm.time.tm_year <= 200) seq_printf(seq, "%04d-", alrm.time.tm_year + 1900); else seq_printf(seq, "****-"); if ((unsigned int)alrm.time.tm_mon <= 11) seq_printf(seq, "%02d-", alrm.time.tm_mon + 1); else seq_printf(seq, "**-"); if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31) seq_printf(seq, "%02d\n", alrm.time.tm_mday); else seq_printf(seq, "**\n"); seq_printf(seq, "alarm_IRQ\t: %s\n", alrm.enabled ? "yes" : "no"); seq_printf(seq, "alrm_pending\t: %s\n", alrm.pending ? "yes" : "no"); } seq_printf(seq, "24hr\t\t: yes\n"); if (ops->proc) ops->proc(class_dev->dev, seq); return 0; }
static int rtc_resume(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; struct timespec new_system, new_rtc; struct timespec sleep_time; if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; #if defined(ADJUST_KERNEL_TIME) printk("%s [RTC] ==================================== \n", __func__); #endif /* snapshot the current rtc and system time at resume */ getnstimeofday(&new_system); rtc_read_time(rtc, &tm); if (rtc_valid_tm(&tm) != 0) { pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); return 0; } rtc_tm_to_time(&tm, &new_rtc.tv_sec); new_rtc.tv_nsec = 0; if (new_rtc.tv_sec < old_rtc.tv_sec) { pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); return 0; } /* calculate the RTC time delta (sleep time)*/ sleep_time = timespec_sub(new_rtc, old_rtc); /* * Since these RTC suspend/resume handlers are not called * at the very end of suspend or the start of resume, * some run-time may pass on either sides of the sleep time * so subtract kernel run-time between rtc_suspend to rtc_resume * to keep things accurate. */ sleep_time = timespec_sub(sleep_time, timespec_sub(new_system, old_system)); if (sleep_time.tv_sec >= 0) timekeeping_inject_sleeptime(&sleep_time); #ifdef ADJUST_KERNEL_TIME schedule_delayed_work(&rtc_work, RTC_WORK_CHECK_TIMEOUT); #endif #if defined(ADJUST_KERNEL_TIME) printk("%s [RTC] sleep_time = %ld \n", __func__,sleep_time.tv_sec); printk("%s [RTC] time now = %ld\n", __func__,new_rtc.tv_sec); printk("%s [RTC] ==================================== \n", __func__); #endif return 0; }
/** * has_readtime - check rtc device has readtime ability * @dev: current device * @name_ptr: name to be returned * * This helper function checks to see if the rtc device can be * used for reading time */ static int has_readtime(struct device *dev, void *name_ptr) { struct rtc_device *candidate = to_rtc_device(dev); if (!candidate->ops->read_time) return 0; return 1; }
/* The reason to trigger an alarm with no process watching it (via sysfs) * is its side effect: waking from a system state like suspend-to-RAM or * suspend-to-disk. So: no attribute unless that side effect is possible. * (Userspace may disable that mechanism later.) */ static inline int rtc_does_wakealarm(struct class_device *class_dev) { struct rtc_device *rtc; if (!device_can_wakeup(class_dev->dev)) return 0; rtc = to_rtc_device(class_dev); return rtc->ops->set_alarm != NULL; }
static ssize_t rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { ssize_t retval; unsigned long now, alarm; struct rtc_wkalrm alm; struct rtc_device *rtc = to_rtc_device(dev); char *buf_ptr; int adjust = 0; printk("%s \n", __func__); /* Only request alarms that trigger in the future. Disable them * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. */ retval = rtc_read_time(rtc, &alm.time); sys_out("retval is %d \n", retval); if (retval < 0) return retval; rtc_tm_to_time(&alm.time, &now); buf_ptr = (char *)buf; if (*buf_ptr == '+') { buf_ptr++; adjust = 1; } alarm = simple_strtoul(buf_ptr, NULL, 0); if (adjust) { alarm += now; } if (alarm > now) { /* Avoid accidentally clobbering active alarms; we can't * entirely prevent that here, without even the minimal * locking from the /dev/rtcN api. */ retval = rtc_read_alarm(rtc, &alm); if (retval < 0) return retval; if (alm.enabled) return -EBUSY; alm.enabled = 1; } else { alm.enabled = 0; /* Provide a valid future alarm time. Linux isn't EFI, * this time won't be ignored when disabling the alarm. */ alarm = now + 300; } rtc_time_to_tm(alarm, &alm.time); retval = rtc_set_alarm(rtc, &alm); printk("set_alarm retval: %d\n",retval); return (retval < 0) ? retval : n; }
static int __init has_wakealarm(struct device *dev, const void *data) { struct rtc_device *candidate = to_rtc_device(dev); if (!candidate->ops->set_alarm) return 0; if (!device_may_wakeup(candidate->dev.parent)) return 0; return 1; }
static int __init has_wakealarm(struct device *dev, void *name_ptr) { struct rtc_device *candidate = to_rtc_device(dev); if (!candidate->ops->set_alarm) return 0; if (!device_may_wakeup(candidate->dev.parent)) return 0; *(const char **)name_ptr = dev_name(dev); return 1; }
/** * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time * * Returns 1 if the system clock was set by this RTC at the last * boot or resume event. */ static ssize_t hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) { #ifdef CONFIG_RTC_HCTOSYS_DEVICE if (rtc_hctosys_ret == 0 && strcmp(dev_name(&to_rtc_device(dev)->dev), CONFIG_RTC_HCTOSYS_DEVICE) == 0) return sprintf(buf, "1\n"); else #endif return sprintf(buf, "0\n"); }
static ssize_t offset_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; long offset; retval = rtc_read_offset(to_rtc_device(dev), &offset); if (retval == 0) retval = sprintf(buf, "%ld\n", offset); return retval; }
/** * alarmpwr_get_rtcdev - Return power up rtcdevice * * This function returns the rtc device to power up for wakealarms. * If one has not already been chosen, it checks to see if a * functional rtc device is available. */ struct rtc_device *alarmpwr_get_rtcdev(void) { struct rtc_device *ret; struct device *dev; dev = class_find_device(rtc_class, NULL, NULL, rtc_match); if (dev == NULL) return NULL; ret = to_rtc_device(dev); return ret; }
static ssize_t offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { ssize_t retval; long offset; retval = kstrtol(buf, 10, &offset); if (retval == 0) retval = rtc_set_offset(to_rtc_device(dev), offset); return (retval < 0) ? retval : n; }
static ssize_t time_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; struct rtc_time tm; retval = rtc_read_time(to_rtc_device(dev), &tm); if (retval == 0) { retval = sprintf(buf, "%02d:%02d:%02d\n", tm.tm_hour, tm.tm_min, tm.tm_sec); } return retval; }
static ssize_t date_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; struct rtc_time tm; retval = rtc_read_time(to_rtc_device(dev), &tm); if (retval == 0) { retval = sprintf(buf, "%04d-%02d-%02d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); } return retval; }
static ssize_t rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { struct rtc_device *rtc = to_rtc_device(dev); unsigned long val = simple_strtoul(buf, NULL, 0); if (val >= 4096 || val == 0) return -EINVAL; rtc->max_user_freq = (int)val; return n; }
static ssize_t since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; struct rtc_time tm; retval = rtc_read_time(to_rtc_device(dev), &tm); if (retval == 0) { unsigned long time; rtc_tm_to_time(&tm, &time); retval = sprintf(buf, "%lu\n", time); } return retval; }
static ssize_t rtc_sysfs_show_alarm_boot(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; struct rtc_wkalrm alm; retval = rtc_get_bootalarm(to_rtc_device(dev), &alm); if (retval) { retval = sprintf(buf, "%d", alm.enabled); pr_info("%s [SAPA] rtc_sysfs_show_wakealarm enabled? : %d\n",__func__,alm.enabled); return retval; } return retval; }
static ssize_t rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; unsigned long alarm; struct rtc_wkalrm alm; retval = rtc_read_alarm(to_rtc_device(dev), &alm); if (retval == 0 && alm.enabled) { rtc_tm_to_time(&alm.time, &alarm); retval = sprintf(buf, "%lu\n", alarm); } return retval; }
static umode_t rtc_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); struct rtc_device *rtc = to_rtc_device(dev); umode_t mode = attr->mode; if (attr == &dev_attr_wakealarm.attr) { if (!rtc_does_wakealarm(rtc)) mode = 0; } else if (attr == &dev_attr_offset.attr) { if (!rtc->ops->set_offset) mode = 0; } return mode; }
static ssize_t rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { ssize_t retval; unsigned long now, alarm; struct rtc_wkalrm alm; struct rtc_device *rtc = to_rtc_device(dev); char *buf_ptr; int adjust = 0; retval = rtc_read_time(rtc, &alm.time); if (retval < 0) return retval; rtc_tm_to_time(&alm.time, &now); buf_ptr = (char *)buf; if (*buf_ptr == '+') { buf_ptr++; adjust = 1; } alarm = simple_strtoul(buf_ptr, NULL, 0); if (adjust) { alarm += now; } if (alarm > now) { retval = rtc_read_alarm(rtc, &alm); if (retval < 0) return retval; if (alm.enabled) return -EBUSY; alm.enabled = 1; } else { alm.enabled = 0; alarm = now + 300; } rtc_time_to_tm(alarm, &alm.time); retval = rtc_set_alarm(rtc, &alm); return (retval < 0) ? retval : n; }
struct rtc_device *rtc_class_open(const char *name) { struct device *dev; struct rtc_device *rtc = NULL; dev = class_find_device(rtc_class, NULL, name, __rtc_match); if (dev) rtc = to_rtc_device(dev); if (rtc) { if (!try_module_get(rtc->owner)) { put_device(dev); rtc = NULL; } } return rtc; }
static ssize_t rtc_sysfs_show_alarm_boot(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; unsigned long alarm; struct rtc_wkalrm alm; retval = rtc_get_alarm_boot(to_rtc_device(dev), &alm); if (retval) { retval = sprintf(buf, "%d", alm.enabled); printk(KERN_INFO "rtc_sysfs_show_wakealarm enabled? : %d\n", alm.enabled); return retval; } return retval; }
static ssize_t max_user_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { struct rtc_device *rtc = to_rtc_device(dev); unsigned long val; int err; err = kstrtoul(buf, 0, &val); if (err) return err; if (val >= 4096 || val == 0) return -EINVAL; rtc->max_user_freq = (int)val; return n; }
static int alarmtimer_rtc_add_device(struct device *dev, struct class_interface *class_intf) { unsigned long flags; struct rtc_device *rtc = to_rtc_device(dev); if (rtcdev) return -EBUSY; if (!rtc->ops->set_alarm) return -1; spin_lock_irqsave(&rtcdev_lock, flags); if (!rtcdev) { rtcdev = rtc; /* hold a reference so it doesn't go away */ get_device(dev); } spin_unlock_irqrestore(&rtcdev_lock, flags); return 0; }
static ssize_t wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; time64_t alarm; struct rtc_wkalrm alm; /* Don't show disabled alarms. For uniformity, RTC alarms are * conceptually one-shot, even though some common RTCs (on PCs) * don't actually work that way. * * NOTE: RTC implementations where the alarm doesn't match an * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC * alarms after they trigger, to ensure one-shot semantics. */ retval = rtc_read_alarm(to_rtc_device(dev), &alm); if (retval == 0 && alm.enabled) { alarm = rtc_tm_to_time64(&alm.time); retval = sprintf(buf, "%lld\n", alarm); } return retval; }
static ssize_t rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); }