예제 #1
0
파일: rtc-test.c 프로젝트: 020gzh/linux
static ssize_t test_irq_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	int retval;
	struct platform_device *plat_dev = to_platform_device(dev);
	struct rtc_device *rtc = platform_get_drvdata(plat_dev);

	retval = count;
	if (strncmp(buf, "tick", 4) == 0 && rtc->pie_enabled)
		rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF);
	else if (strncmp(buf, "alarm", 5) == 0) {
		struct rtc_wkalrm alrm;
		int err = rtc_read_alarm(rtc, &alrm);

		if (!err && alrm.enabled)
			rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);

	} else if (strncmp(buf, "update", 6) == 0 && rtc->uie_rtctimer.enabled)
		rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF);
	else
		retval = -EINVAL;

	return retval;
}
예제 #2
0
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 suspend_autotest_suspend(struct device *dev)
{
	unsigned long now;
	struct rtc_wkalrm alm;
	int status;
	int need_test = 0;
	unsigned long alarm_time;

	/* if test isn't enabled, no need to proceed below code */
	if ((!test_enable) || (test_mode != SUSPEND))
		return 0;

	/* read alarm time */
	status = rtc_read_alarm(rtc, &alm);
	if (status) {
		pr_info("%s: rtc_read_alarm fail\n", __func__);
		return status;
	}

	rtc_tm_to_time(&alm.time, &alarm_time);
	/* if alarm is set already, alarm time should be compared.
	 * if no alarm is set, test alarm can be done.
	 */
	if (alm.enabled)
		need_test = 0;
	else
		need_test = 1;

	status = rtc_read_time(rtc, &alm.time);
	if (status < 0) {
		pr_info("%s: rtc_read_time fail\n", __func__);
		return status;
	}
	rtc_tm_to_time(&alm.time, &now);

	/* if alarm will be expired in TEST_SUSPEND_SECONDS,
	 * don't set test alarm time
	 */
	if (!need_test && alarm_time < (now + TEST_SUSPEND_SECONDS)) {
		pr_info("%s: no setting of test alarm\n", __func__);
		return 0;
	}

	memset(&alm, 0, sizeof alm);
	rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
	alm.enabled = true;

	status = rtc_set_alarm(rtc, &alm);
	if (status < 0) {
		pr_info("%s: rtc_set_alarm fail\n",__func__);
		return status;
	}

	test_alarm_set = 1;
	pr_info("%s: test alarm will be envoked after about %d sec.\n",
			__func__, TEST_SUSPEND_SECONDS);

	return 0;
}
예제 #4
0
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;
}
예제 #5
0
파일: rtctime.c 프로젝트: ena30/snake-os
static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	struct rtc_ops *ops = data;
	struct rtc_wkalrm alrm;
	struct rtc_time tm;
	char *p = page;

	if (rtc_read_time(ops, &tm) == 0) {
		p += sprintf(p,
			"rtc_time\t: %02d:%02d:%02d\n"
			"rtc_date\t: %04d-%02d-%02d\n"
			"rtc_epoch\t: %04lu\n",
			tm.tm_hour, tm.tm_min, tm.tm_sec,
			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
			rtc_epoch);
	}

	if (rtc_read_alarm(ops, &alrm) == 0) {
		p += sprintf(p, "alrm_time\t: ");
		if ((unsigned int)alrm.time.tm_hour <= 24)
			p += sprintf(p, "%02d:", alrm.time.tm_hour);
		else
			p += sprintf(p, "**:");
		if ((unsigned int)alrm.time.tm_min <= 59)
			p += sprintf(p, "%02d:", alrm.time.tm_min);
		else
			p += sprintf(p, "**:");
		if ((unsigned int)alrm.time.tm_sec <= 59)
			p += sprintf(p, "%02d\n", alrm.time.tm_sec);
		else
			p += sprintf(p, "**\n");

		p += sprintf(p, "alrm_date\t: ");
		if ((unsigned int)alrm.time.tm_year <= 200)
			p += sprintf(p, "%04d-", alrm.time.tm_year + 1900);
		else
			p += sprintf(p, "****-");
		if ((unsigned int)alrm.time.tm_mon <= 11)
			p += sprintf(p, "%02d-", alrm.time.tm_mon + 1);
		else
			p += sprintf(p, "**-");
		if ((unsigned int)alrm.time.tm_mday <= 31)
			p += sprintf(p, "%02d\n", alrm.time.tm_mday);
		else
			p += sprintf(p, "**\n");
		p += sprintf(p, "alrm_wakeup\t: %s\n",
			     alrm.enabled ? "yes" : "no");
		p += sprintf(p, "alrm_pending\t: %s\n",
			     alrm.pending ? "yes" : "no");
	}

	if (ops->proc)
		p += ops->proc(p);

	return p - page;
}
예제 #6
0
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;
}
예제 #7
0
static int set_wakealarm(void)
{
	int retval = 0;
	unsigned long now, alarm;
	struct rtc_wkalrm alm;
	struct rtc_device *rtc;

	rtc = rtc_class_open(CONFIG_WAKEALARM_RTC);
	if (!rtc) {
		return -1;
	}

	/* 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);
	if (retval < 0)
		goto close_rtc;
	rtc_tm_to_time(&alm.time, &now);

	alarm = now + sleep_time;
	
	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)
			goto close_rtc;

		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);

close_rtc:
	rtc_class_close(rtc);
	return retval;
}
예제 #8
0
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;
}
예제 #9
0
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;
}
int alarm_read_rtc_ring(int *flag, unsigned long *alarm_time)
{
    struct rtc_wkalrm rtc_alarm;
    int ret = 0;

    if (pwr_rtc_dev != NULL) {
        if (pwr_rtc_dev->dev.platform_data)
            *flag = *(int *)(pwr_rtc_dev->dev.platform_data);
        ret = rtc_read_alarm(pwr_rtc_dev, &rtc_alarm);
        if (ret < 0)
            goto out;
        rtc_tm_to_time(&rtc_alarm.time, alarm_time);
        pr_alarm(INT, "%s, flag: %d, alarm time: %lu\n",
                 __func__, *flag, *alarm_time);
    }
out:
    return ret;
}
예제 #11
0
static ssize_t
rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n)
{
	ssize_t retval;
	unsigned long now, alarm;
	struct rtc_wkalrm alm;

	/* 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(dev, &alm.time);
	if (retval < 0)
		return retval;
	rtc_tm_to_time(&alm.time, &now);

	alarm = simple_strtoul(buf, NULL, 0);
	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(dev, &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(dev, &alm);
	return (retval < 0) ? retval : n;
}
예제 #12
0
void power_on_alarm_init(void)
{
	struct rtc_wkalrm rtc_alarm;
	struct rtc_time rt;
	unsigned long alarm_time;
	struct rtc_device *rtc;

	rtc = alarmtimer_get_rtcdev();

	/* If we have no rtcdev, just return */
	if (!rtc)
		return;

	rtc_read_alarm(rtc, &rtc_alarm);
	rt = rtc_alarm.time;

	rtc_tm_to_time(&rt, &alarm_time);

	if (alarm_time)
		power_on_alarm = alarm_time;
	else
		power_on_alarm = 0;
}
예제 #13
0
static ssize_t
rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf)
{
	ssize_t retval;
	unsigned long alarm;
	struct rtc_wkalrm alm;

	/* Don't show disabled alarms; but the RTC could leave the
	 * alarm enabled after it's already triggered.  Alarms are
	 * conceptually one-shot, even though some common hardware
	 * (PCs) doesn't actually work that way.
	 *
	 * REVISIT maybe we should require RTC implementations to
	 * disable the RTC alarm after it triggers, for uniformity.
	 */
	retval = rtc_read_alarm(dev, &alm);
	if (retval == 0 && alm.enabled) {
		rtc_tm_to_time(&alm.time, &alarm);
		retval = sprintf(buf, "%lu\n", alarm);
	}

	return retval;
}
예제 #14
0
파일: rtc-sysfs.c 프로젝트: Lyude/linux
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_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;

	/* Only request alarms that trigger in the future.  Disable them
	 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
	 */
	printk("rtc_sysfs_set_wakealarm is enter,buf=%s,n=%d,zte_rtc_alarm_en=%d\n",buf,n,zte_rtc_alarm_en);

	zte_rtc_alarm_en=0;
	
	retval = rtc_read_time(rtc, &alm.time);
	if (retval < 0)
	{     
	       printk("rtc_sysfs_set_wakealarm is error1 return=%d\n",retval);
		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 /= MSEC_PER_SEC;
		alarm += now;
	}

	 printk("rtc_sysfs_set_wakealarm:alarm=%ld,now=%ld\n",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)
		{
		       printk("rtc_sysfs_set_wakealarm is error2 return=%d\n",retval);
			return retval;
		}
#if 0		
		if (alm.enabled)
		{
		        printk("rtc_sysfs_set_wakealarm is error3 return=-EBUSY\n");
			return -EBUSY;
		}
#endif		

              zte_rtc_alarm_en=1;
		alm.enabled = 1;
		setup_hibernate_alarm(rtc, (alarm - now));
	} 
	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;
		setup_hibernate_alarm(rtc, 0);
	}
	rtc_time_to_tm(alarm, &alm.time);

	retval = rtc_set_alarm(rtc, &alm);
	printk("rtc_sysfs_set_wakealarm is ok return=%d,zte_rtc_alarm_en=%d\n",retval,zte_rtc_alarm_en);
	
	return (retval < 0) ? retval : n;
}
static int rtc_proc_show(struct seq_file *seq, void *offset)
{
	int err;
	struct rtc_device *rtc = seq->private;
	const struct rtc_class_ops *ops = rtc->ops;
	struct rtc_wkalrm alrm;
	struct rtc_time tm;

	err = rtc_read_time(rtc, &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(rtc, &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, "update IRQ enabled\t: %s\n",
			(rtc->uie_rtctimer.enabled) ? "yes" : "no");
		seq_printf(seq, "periodic IRQ enabled\t: %s\n",
			(rtc->pie_enabled) ? "yes" : "no");
		seq_printf(seq, "periodic IRQ frequency\t: %d\n",
			rtc->irq_freq);
		seq_printf(seq, "max user IRQ frequency\t: %d\n",
			rtc->max_user_freq);
	}

	seq_printf(seq, "24hr\t\t: yes\n");

	if (ops->proc)
		ops->proc(rtc->dev.parent, seq);

	return 0;
}
예제 #17
0
파일: rtctime.c 프로젝트: ena30/snake-os
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
		     unsigned long arg)
{
	struct rtc_ops *ops = file->private_data;
	struct rtc_time tm;
	struct rtc_wkalrm alrm;
	void __user *uarg = (void __user *)arg;
	int ret = -EINVAL;

	switch (cmd) {
	case RTC_ALM_READ:
		ret = rtc_read_alarm(ops, &alrm);
		if (ret)
			break;
		ret = copy_to_user(uarg, &alrm.time, sizeof(tm));
		if (ret)
			ret = -EFAULT;
		break;

	case RTC_ALM_SET:
		ret = copy_from_user(&alrm.time, uarg, sizeof(tm));
		if (ret) {
			ret = -EFAULT;
			break;
		}
		alrm.enabled = 0;
		alrm.pending = 0;
		alrm.time.tm_mday = -1;
		alrm.time.tm_mon = -1;
		alrm.time.tm_year = -1;
		alrm.time.tm_wday = -1;
		alrm.time.tm_yday = -1;
		alrm.time.tm_isdst = -1;
		ret = rtc_set_alarm(ops, &alrm);
		break;

	case RTC_RD_TIME:
		ret = rtc_read_time(ops, &tm);
		if (ret)
			break;
		ret = copy_to_user(uarg, &tm, sizeof(tm));
		if (ret)
			ret = -EFAULT;
		break;

	case RTC_SET_TIME:
		if (!capable(CAP_SYS_TIME)) {
			ret = -EACCES;
			break;
		}
		ret = copy_from_user(&tm, uarg, sizeof(tm));
		if (ret) {
			ret = -EFAULT;
			break;
		}
		ret = rtc_set_time(ops, &tm);
		break;

	case RTC_EPOCH_SET:
#ifndef rtc_epoch
		/*
		 * There were no RTC clocks before 1900.
		 */
		if (arg < 1900) {
			ret = -EINVAL;
			break;
		}
		if (!capable(CAP_SYS_TIME)) {
			ret = -EACCES;
			break;
		}
		rtc_epoch = arg;
		ret = 0;
#endif
		break;

	case RTC_EPOCH_READ:
		ret = put_user(rtc_epoch, (unsigned long __user *)uarg);
		break;

	case RTC_WKALM_SET:
		ret = copy_from_user(&alrm, uarg, sizeof(alrm));
		if (ret) {
			ret = -EFAULT;
			break;
		}
		ret = rtc_set_alarm(ops, &alrm);
		break;

	case RTC_WKALM_RD:
		ret = rtc_read_alarm(ops, &alrm);
		if (ret)
			break;
		ret = copy_to_user(uarg, &alrm, sizeof(alrm));
		if (ret)
			ret = -EFAULT;
		break;

	default:
		if (ops->ioctl)
			ret = ops->ioctl(cmd, arg);
		break;
	}
	return ret;
}
예제 #18
0
파일: rtc-sysfs.c 프로젝트: mdamt/linux
static ssize_t
wakealarm_store(struct device *dev, struct device_attribute *attr,
		const char *buf, size_t n)
{
	ssize_t retval;
	unsigned long now, alarm;
	unsigned long push = 0;
	struct rtc_wkalrm alm;
	struct rtc_device *rtc = to_rtc_device(dev);
	const char *buf_ptr;
	int adjust = 0;

	/* 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);
	if (retval < 0)
		return retval;
	rtc_tm_to_time(&alm.time, &now);

	buf_ptr = buf;
	if (*buf_ptr == '+') {
		buf_ptr++;
		if (*buf_ptr == '=') {
			buf_ptr++;
			push = 1;
		} else
			adjust = 1;
	}
	retval = kstrtoul(buf_ptr, 0, &alarm);
	if (retval)
		return retval;
	if (adjust) {
		alarm += now;
	}
	if (alarm > now || push) {
		/* 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) {
			if (push) {
				rtc_tm_to_time(&alm.time, &push);
				alarm += push;
			} else
				return -EBUSY;
		} else if (push)
			return -EINVAL;
		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);
	return (retval < 0) ? retval : n;
}