Firstly enable ioctl in ppdev and then Keep par_timeout as timeval in compat ioctl in order to use the 64bit time type.
Signed-off-by: Bamvor Zhang Jian bamvor.zhangjian@linaro.org --- This is my first time to try to upstream some code in kernel. Any commit and feedback is welcome.
drivers/char/ppdev.c | 30 +++++++++++++++++++++++++----- include/uapi/linux/ppdev.h | 20 ++++++++++++++++++-- 2 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index ae0b42b..9e3c101 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -69,6 +69,7 @@ #include <linux/ppdev.h> #include <linux/mutex.h> #include <linux/uaccess.h> +#include <linux/compat.h>
#define PP_VERSION "ppdev: user-space parallel port driver" #define CHRDEV "ppdev" @@ -592,9 +593,17 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) atomic_sub (ret, &pp->irqc); return 0;
- case PPSETTIME: - if (copy_from_user (&par_timeout, argp, sizeof(struct timeval))) { - return -EFAULT; +#ifdef PPSETTIME64 + case PPSETTIME64: +#endif /* PPSETTIME64 */ + case PPSETTIME32: + if (!IS_ENABLED(CONFIG_64BIT) || is_compat_task()) { + if (compat_get_timeval(&par_timeout, compat_ptr(arg))) + return -EFAULT; + } else { + if (copy_from_user(&par_timeout, argp, + sizeof(par_timeout))) + return -EFAULT; } /* Convert to jiffies, place in pp->pdev->timeout */ if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) { @@ -608,13 +617,23 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) pp->pdev->timeout = to_jiffies; return 0;
- case PPGETTIME: +#ifdef PPGETTIME64 + case PPGETTIME64: +#endif /* PPGETTIME64 */ + case PPGETTIME32: to_jiffies = pp->pdev->timeout; memset(&par_timeout, 0, sizeof(par_timeout)); par_timeout.tv_sec = to_jiffies / HZ; par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ); - if (copy_to_user (argp, &par_timeout, sizeof(struct timeval))) return -EFAULT; + if (!IS_ENABLED(CONFIG_64BIT) || is_compat_task()) { + if (compat_put_timeval(&par_timeout, compat_ptr(arg))) + return -EFAULT; + } else { + if (copy_to_user(argp, &par_timeout, + sizeof(par_timeout))) + return -EFAULT; + } return 0;
default: @@ -744,6 +763,7 @@ static const struct file_operations pp_fops = { .write = pp_write, .poll = pp_poll, .unlocked_ioctl = pp_ioctl, + .compat_ioctl = pp_ioctl, .open = pp_open, .release = pp_release, }; diff --git a/include/uapi/linux/ppdev.h b/include/uapi/linux/ppdev.h index dc18c5d..f4c8fac 100644 --- a/include/uapi/linux/ppdev.h +++ b/include/uapi/linux/ppdev.h @@ -74,8 +74,24 @@ struct ppdev_frob_struct { #define PPSETPHASE _IOW(PP_IOCTL, 0x94, int)
/* Set and get port timeout (struct timeval's) */ -#define PPGETTIME _IOR(PP_IOCTL, 0x95, struct timeval) -#define PPSETTIME _IOW(PP_IOCTL, 0x96, struct timeval) +#ifdef CONFIG_64BIT +#define PPGETTIME PPGETTIME64 +#define PPSETTIME PPSETTIME64 +#define PPGETTIME64 _IOR(PP_IOCTL, 0x95, struct timeval) +#define PPSETTIME64 _IOW(PP_IOCTL, 0x96, struct timeval) +#define PPGETTIME32 _IOR(PP_IOCTL, 0x9c, struct compat_timeval) +#define PPSETTIME32 _IOW(PP_IOCTL, 0x9d, struct compat_timeval) +#elif defined(CONFIG_COMPAT_TIME) +#define PPGETTIME PPGETTIME32 +#define PPSETTIME PPSETTIME32 +#define PPGETTIME32 _IOR(PP_IOCTL, 0x95, struct compat_timeval) +#define PPSETTIME32 _IOW(PP_IOCTL, 0x96, struct compat_timeval) +#else +#define PPGETTIME PPGETTIME32 +#define PPSETTIME PPSETTIME32 +#define PPGETTIME32 _IOR(PP_IOCTL, 0x95, struct timeval) +#define PPSETTIME32 _IOW(PP_IOCTL, 0x96, struct timeval) +#endif /* CONFIG_64BIT */
/* Get available modes (what the hardware can do) */ #define PPGETMODES _IOR(PP_IOCTL, 0x97, unsigned int)