Commit 3b9ab374 authored by Bamvor Jian Zhang's avatar Bamvor Jian Zhang Committed by Greg Kroah-Hartman

ppdev: convert to y2038 safe

The y2038 issue for ppdev is changes of timeval in the ioctl
(PPSETTIME and PPGETTIME). The size of struct timeval changes from
8bytes to 16bytes due to the changes of time_t. It lead to the
changes of the command of ioctl, e.g. for PPGETTIME, We have:

on 32-bit (old): 0x80087095
on 32-bit (new): 0x80107095
on 64-bit      : 0x80107095

This patch define these two ioctl commands to support the 32bit
and 64bit time_t application at the same time. And, introduce
pp_set_timeout to remove some duplicated code.
Signed-off-by: default avatarBamvor Jian Zhang <bamvor.zhangjian@linaro.org>
Reviewed-by: default avatarArnd Bergmann <arnd@arndb.de>
Tested-by: default avatarSudip Mukherjee <sudipm.mukherjee@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 468623bb
...@@ -98,6 +98,13 @@ struct pp_struct { ...@@ -98,6 +98,13 @@ struct pp_struct {
#define ROUND_UP(x,y) (((x)+(y)-1)/(y)) #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
static DEFINE_MUTEX(pp_do_mutex); static DEFINE_MUTEX(pp_do_mutex);
/* define fixed sized ioctl cmd for y2038 migration */
#define PPGETTIME32 _IOR(PP_IOCTL, 0x95, s32[2])
#define PPSETTIME32 _IOW(PP_IOCTL, 0x96, s32[2])
#define PPGETTIME64 _IOR(PP_IOCTL, 0x95, s64[2])
#define PPSETTIME64 _IOW(PP_IOCTL, 0x96, s64[2])
static inline void pp_enable_irq (struct pp_struct *pp) static inline void pp_enable_irq (struct pp_struct *pp)
{ {
struct parport *port = pp->pdev->port; struct parport *port = pp->pdev->port;
...@@ -322,6 +329,22 @@ static enum ieee1284_phase init_phase (int mode) ...@@ -322,6 +329,22 @@ static enum ieee1284_phase init_phase (int mode)
return IEEE1284_PH_FWD_IDLE; return IEEE1284_PH_FWD_IDLE;
} }
static int pp_set_timeout(struct pardevice *pdev, long tv_sec, int tv_usec)
{
long to_jiffies;
if ((tv_sec < 0) || (tv_usec < 0))
return -EINVAL;
to_jiffies = usecs_to_jiffies(tv_usec);
to_jiffies += tv_sec * HZ;
if (to_jiffies <= 0)
return -EINVAL;
pdev->timeout = to_jiffies;
return 0;
}
static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
unsigned int minor = iminor(file_inode(file)); unsigned int minor = iminor(file_inode(file));
...@@ -495,9 +518,10 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -495,9 +518,10 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned char reg; unsigned char reg;
unsigned char mask; unsigned char mask;
int mode; int mode;
s32 time32[2];
s64 time64[2];
struct timespec64 ts;
int ret; int ret;
struct timeval par_timeout;
long to_jiffies;
case PPRSTATUS: case PPRSTATUS:
reg = parport_read_status (port); reg = parport_read_status (port);
...@@ -592,29 +616,40 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -592,29 +616,40 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
atomic_sub (ret, &pp->irqc); atomic_sub (ret, &pp->irqc);
return 0; return 0;
case PPSETTIME: case PPSETTIME32:
if (copy_from_user (&par_timeout, argp, sizeof(struct timeval))) { if (copy_from_user(time32, argp, sizeof(time32)))
return -EFAULT; return -EFAULT;
}
/* Convert to jiffies, place in pp->pdev->timeout */ return pp_set_timeout(pp->pdev, time32[0], time32[1]);
if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) {
return -EINVAL; case PPSETTIME64:
} if (copy_from_user(time64, argp, sizeof(time64)))
to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ); return -EFAULT;
to_jiffies += par_timeout.tv_sec * (long)HZ;
if (to_jiffies <= 0) { return pp_set_timeout(pp->pdev, time64[0], time64[1]);
case PPGETTIME32:
jiffies_to_timespec64(pp->pdev->timeout, &ts);
time32[0] = ts.tv_sec;
time32[1] = ts.tv_nsec / NSEC_PER_USEC;
if ((time32[0] < 0) || (time32[1] < 0))
return -EINVAL; return -EINVAL;
}
pp->pdev->timeout = to_jiffies; if (copy_to_user(argp, time32, sizeof(time32)))
return -EFAULT;
return 0; return 0;
case PPGETTIME: case PPGETTIME64:
to_jiffies = pp->pdev->timeout; jiffies_to_timespec64(pp->pdev->timeout, &ts);
memset(&par_timeout, 0, sizeof(par_timeout)); time64[0] = ts.tv_sec;
par_timeout.tv_sec = to_jiffies / HZ; time64[1] = ts.tv_nsec / NSEC_PER_USEC;
par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ); if ((time64[0] < 0) || (time64[1] < 0))
if (copy_to_user (argp, &par_timeout, sizeof(struct timeval))) return -EINVAL;
if (copy_to_user(argp, time64, sizeof(time64)))
return -EFAULT; return -EFAULT;
return 0; return 0;
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment