diff options
Diffstat (limited to 'drivers/rtc/dev.c')
-rw-r--r-- | drivers/rtc/dev.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index 5b8ebe86124a..e104972a28fd 100644 --- a/drivers/rtc/dev.c +++ b/drivers/rtc/dev.c @@ -208,6 +208,7 @@ static long rtc_dev_ioctl(struct file *file, const struct rtc_class_ops *ops = rtc->ops; struct rtc_time tm; struct rtc_wkalrm alarm; + struct rtc_param param; void __user *uarg = (void __user *)arg; err = mutex_lock_interruptible(&rtc->ops_lock); @@ -221,6 +222,7 @@ static long rtc_dev_ioctl(struct file *file, switch (cmd) { case RTC_EPOCH_SET: case RTC_SET_TIME: + case RTC_PARAM_SET: if (!capable(CAP_SYS_TIME)) err = -EACCES; break; @@ -382,6 +384,69 @@ static long rtc_dev_ioctl(struct file *file, err = -EFAULT; return err; + case RTC_PARAM_GET: + if (copy_from_user(¶m, uarg, sizeof(param))) { + mutex_unlock(&rtc->ops_lock); + return -EFAULT; + } + + switch(param.param) { + long offset; + case RTC_PARAM_FEATURES: + if (param.index != 0) + err = -EINVAL; + param.uvalue = rtc->features[0]; + break; + + case RTC_PARAM_CORRECTION: + mutex_unlock(&rtc->ops_lock); + if (param.index != 0) + return -EINVAL; + err = rtc_read_offset(rtc, &offset); + mutex_lock(&rtc->ops_lock); + if (err == 0) + param.svalue = offset; + break; + + default: + if (rtc->ops->param_get) + err = rtc->ops->param_get(rtc->dev.parent, ¶m); + else + err = -EINVAL; + } + + if (!err) + if (copy_to_user(uarg, ¶m, sizeof(param))) + err = -EFAULT; + + break; + + case RTC_PARAM_SET: + if (copy_from_user(¶m, uarg, sizeof(param))) { + mutex_unlock(&rtc->ops_lock); + return -EFAULT; + } + + switch(param.param) { + case RTC_PARAM_FEATURES: + err = -EINVAL; + break; + + case RTC_PARAM_CORRECTION: + mutex_unlock(&rtc->ops_lock); + if (param.index != 0) + return -EINVAL; + return rtc_set_offset(rtc, param.svalue); + + default: + if (rtc->ops->param_set) + err = rtc->ops->param_set(rtc->dev.parent, ¶m); + else + err = -EINVAL; + } + + break; + default: /* Finally try the driver's ioctl interface */ if (ops->ioctl) { |