|
@@ -98,6 +98,13 @@ struct pp_struct {
|
|
|
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
|
|
|
|
|
|
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)
|
|
|
{
|
|
|
struct parport *port = pp->pdev->port;
|
|
@@ -322,6 +329,22 @@ static enum ieee1284_phase init_phase (int mode)
|
|
|
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)
|
|
|
{
|
|
|
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)
|
|
|
unsigned char reg;
|
|
|
unsigned char mask;
|
|
|
int mode;
|
|
|
+ s32 time32[2];
|
|
|
+ s64 time64[2];
|
|
|
+ struct timespec64 ts;
|
|
|
int ret;
|
|
|
- struct timeval par_timeout;
|
|
|
- long to_jiffies;
|
|
|
|
|
|
case PPRSTATUS:
|
|
|
reg = parport_read_status (port);
|
|
@@ -592,29 +616,40 @@ 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))) {
|
|
|
+ case PPSETTIME32:
|
|
|
+ if (copy_from_user(time32, argp, sizeof(time32)))
|
|
|
return -EFAULT;
|
|
|
- }
|
|
|
- /* Convert to jiffies, place in pp->pdev->timeout */
|
|
|
- if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
|
|
|
- to_jiffies += par_timeout.tv_sec * (long)HZ;
|
|
|
- if (to_jiffies <= 0) {
|
|
|
+
|
|
|
+ return pp_set_timeout(pp->pdev, time32[0], time32[1]);
|
|
|
+
|
|
|
+ case PPSETTIME64:
|
|
|
+ if (copy_from_user(time64, argp, sizeof(time64)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ 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;
|
|
|
- }
|
|
|
- pp->pdev->timeout = to_jiffies;
|
|
|
+
|
|
|
+ if (copy_to_user(argp, time32, sizeof(time32)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
- case PPGETTIME:
|
|
|
- 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)))
|
|
|
+ case PPGETTIME64:
|
|
|
+ jiffies_to_timespec64(pp->pdev->timeout, &ts);
|
|
|
+ time64[0] = ts.tv_sec;
|
|
|
+ time64[1] = ts.tv_nsec / NSEC_PER_USEC;
|
|
|
+ if ((time64[0] < 0) || (time64[1] < 0))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (copy_to_user(argp, time64, sizeof(time64)))
|
|
|
return -EFAULT;
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
default:
|