|
@@ -209,7 +209,7 @@ static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
|
|
|
return (data != 0) ? (POLLIN | POLLRDNORM) : 0;
|
|
|
}
|
|
|
|
|
|
-static int rtc_dev_ioctl(struct inode *inode, struct file *file,
|
|
|
+static long rtc_dev_ioctl(struct file *file,
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
|
int err = 0;
|
|
@@ -219,6 +219,10 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
|
|
|
struct rtc_wkalrm alarm;
|
|
|
void __user *uarg = (void __user *) arg;
|
|
|
|
|
|
+ err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
|
+ if (err)
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
/* check that the calling task has appropriate permissions
|
|
|
* for certain ioctls. doing this check here is useful
|
|
|
* to avoid duplicate code in each driver.
|
|
@@ -227,26 +231,31 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
|
|
|
case RTC_EPOCH_SET:
|
|
|
case RTC_SET_TIME:
|
|
|
if (!capable(CAP_SYS_TIME))
|
|
|
- return -EACCES;
|
|
|
+ err = -EACCES;
|
|
|
break;
|
|
|
|
|
|
case RTC_IRQP_SET:
|
|
|
if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
|
|
|
- return -EACCES;
|
|
|
+ err = -EACCES;
|
|
|
break;
|
|
|
|
|
|
case RTC_PIE_ON:
|
|
|
if (rtc->irq_freq > rtc->max_user_freq &&
|
|
|
!capable(CAP_SYS_RESOURCE))
|
|
|
- return -EACCES;
|
|
|
+ err = -EACCES;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ if (err)
|
|
|
+ goto done;
|
|
|
+
|
|
|
/* try the driver's ioctl interface */
|
|
|
if (ops->ioctl) {
|
|
|
err = ops->ioctl(rtc->dev.parent, cmd, arg);
|
|
|
- if (err != -ENOIOCTLCMD)
|
|
|
+ if (err != -ENOIOCTLCMD) {
|
|
|
+ mutex_unlock(&rtc->ops_lock);
|
|
|
return err;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* if the driver does not provide the ioctl interface
|
|
@@ -265,15 +274,19 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
|
|
|
|
|
|
switch (cmd) {
|
|
|
case RTC_ALM_READ:
|
|
|
+ mutex_unlock(&rtc->ops_lock);
|
|
|
+
|
|
|
err = rtc_read_alarm(rtc, &alarm);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
|
|
|
if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
|
|
|
- return -EFAULT;
|
|
|
- break;
|
|
|
+ err = -EFAULT;
|
|
|
+ return err;
|
|
|
|
|
|
case RTC_ALM_SET:
|
|
|
+ mutex_unlock(&rtc->ops_lock);
|
|
|
+
|
|
|
if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
|
|
|
return -EFAULT;
|
|
|
|
|
@@ -321,24 +334,26 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- err = rtc_set_alarm(rtc, &alarm);
|
|
|
- break;
|
|
|
+ return rtc_set_alarm(rtc, &alarm);
|
|
|
|
|
|
case RTC_RD_TIME:
|
|
|
+ mutex_unlock(&rtc->ops_lock);
|
|
|
+
|
|
|
err = rtc_read_time(rtc, &tm);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
|
|
|
if (copy_to_user(uarg, &tm, sizeof(tm)))
|
|
|
- return -EFAULT;
|
|
|
- break;
|
|
|
+ err = -EFAULT;
|
|
|
+ return err;
|
|
|
|
|
|
case RTC_SET_TIME:
|
|
|
+ mutex_unlock(&rtc->ops_lock);
|
|
|
+
|
|
|
if (copy_from_user(&tm, uarg, sizeof(tm)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- err = rtc_set_time(rtc, &tm);
|
|
|
- break;
|
|
|
+ return rtc_set_time(rtc, &tm);
|
|
|
|
|
|
case RTC_PIE_ON:
|
|
|
err = rtc_irq_set_state(rtc, NULL, 1);
|
|
@@ -376,34 +391,37 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
|
|
|
break;
|
|
|
#endif
|
|
|
case RTC_WKALM_SET:
|
|
|
+ mutex_unlock(&rtc->ops_lock);
|
|
|
if (copy_from_user(&alarm, uarg, sizeof(alarm)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- err = rtc_set_alarm(rtc, &alarm);
|
|
|
- break;
|
|
|
+ return rtc_set_alarm(rtc, &alarm);
|
|
|
|
|
|
case RTC_WKALM_RD:
|
|
|
+ mutex_unlock(&rtc->ops_lock);
|
|
|
err = rtc_read_alarm(rtc, &alarm);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
|
|
|
if (copy_to_user(uarg, &alarm, sizeof(alarm)))
|
|
|
- return -EFAULT;
|
|
|
- break;
|
|
|
+ err = -EFAULT;
|
|
|
+ return err;
|
|
|
|
|
|
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
|
|
|
case RTC_UIE_OFF:
|
|
|
clear_uie(rtc);
|
|
|
- return 0;
|
|
|
+ break;
|
|
|
|
|
|
case RTC_UIE_ON:
|
|
|
- return set_uie(rtc);
|
|
|
+ err = set_uie(rtc);
|
|
|
#endif
|
|
|
default:
|
|
|
err = -ENOTTY;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+done:
|
|
|
+ mutex_unlock(&rtc->ops_lock);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -432,7 +450,7 @@ static const struct file_operations rtc_dev_fops = {
|
|
|
.llseek = no_llseek,
|
|
|
.read = rtc_dev_read,
|
|
|
.poll = rtc_dev_poll,
|
|
|
- .ioctl = rtc_dev_ioctl,
|
|
|
+ .unlocked_ioctl = rtc_dev_ioctl,
|
|
|
.open = rtc_dev_open,
|
|
|
.release = rtc_dev_release,
|
|
|
.fasync = rtc_dev_fasync,
|