Merge tag 'sound-fix-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[linux-2.6-microblaze.git] / drivers / rtc / dev.c
index 5b8ebe8..e104972 100644 (file)
@@ -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(&param, 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, &param);
+                       else
+                               err = -EINVAL;
+               }
+
+               if (!err)
+                       if (copy_to_user(uarg, &param, sizeof(param)))
+                               err = -EFAULT;
+
+               break;
+
+       case RTC_PARAM_SET:
+               if (copy_from_user(&param, 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, &param);
+                       else
+                               err = -EINVAL;
+               }
+
+               break;
+
        default:
                /* Finally try the driver's ioctl interface */
                if (ops->ioctl) {