From: Jaedon Shin <jaedon.s...@gmail.com>

commit 18192a77f0810933ab71a46c1b260d230d7352ee upstream

The dtv_properties structure and the dtv_property structure are
different sizes in 32-bit and 64-bit system. This patch provides
FE_SET_PROPERTY and FE_GET_PROPERTY ioctl commands implementation for
32-bit user space applications.

Signed-off-by: Jaedon Shin <jaedon.s...@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mche...@s-opensource.com>
Signed-off-by: Florian Fainelli <f.faine...@gmail.com>
---
 drivers/media/dvb-core/dvb_frontend.c | 131 ++++++++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/drivers/media/dvb-core/dvb_frontend.c 
b/drivers/media/dvb-core/dvb_frontend.c
index c0a25cd6ccb8..34f55a2ba071 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -1983,9 +1983,140 @@ static long dvb_frontend_ioctl(struct file *file, 
unsigned int cmd,
 }
 
 #ifdef CONFIG_COMPAT
+struct compat_dtv_property {
+       __u32 cmd;
+       __u32 reserved[3];
+       union {
+               __u32 data;
+               struct dtv_fe_stats st;
+               struct {
+                       __u8 data[32];
+                       __u32 len;
+                       __u32 reserved1[3];
+                       compat_uptr_t reserved2;
+               } buffer;
+       } u;
+       int result;
+} __attribute__ ((packed));
+
+struct compat_dtv_properties {
+       __u32 num;
+       compat_uptr_t props;
+};
+
+#define COMPAT_FE_SET_PROPERTY    _IOW('o', 82, struct compat_dtv_properties)
+#define COMPAT_FE_GET_PROPERTY    _IOR('o', 83, struct compat_dtv_properties)
+
+static int dvb_frontend_handle_compat_ioctl(struct file *file, unsigned int 
cmd,
+                                           unsigned long arg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       int i, err = 0;
+
+       if (cmd == COMPAT_FE_SET_PROPERTY) {
+               struct compat_dtv_properties prop, *tvps = NULL;
+               struct compat_dtv_property *tvp = NULL;
+
+               if (copy_from_user(&prop, compat_ptr(arg), sizeof(prop)))
+                       return -EFAULT;
+
+               tvps = &prop;
+
+               /*
+                * Put an arbitrary limit on the number of messages that can
+                * be sent at once
+                */
+               if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = memdup_user(compat_ptr(tvps->props), tvps->num * 
sizeof(*tvp));
+               if (IS_ERR(tvp))
+                       return PTR_ERR(tvp);
+
+               for (i = 0; i < tvps->num; i++) {
+                       err = dtv_property_process_set(fe, file,
+                                                       (tvp + i)->cmd,
+                                                       (tvp + i)->u.data);
+                       if (err < 0) {
+                               kfree(tvp);
+                               return err;
+                       }
+               }
+               kfree(tvp);
+       } else if (cmd == COMPAT_FE_GET_PROPERTY) {
+               struct compat_dtv_properties prop, *tvps = NULL;
+               struct compat_dtv_property *tvp = NULL;
+               struct dtv_frontend_properties getp = fe->dtv_property_cache;
+
+               if (copy_from_user(&prop, compat_ptr(arg), sizeof(prop)))
+                       return -EFAULT;
+
+               tvps = &prop;
+
+               /*
+                * Put an arbitrary limit on the number of messages that can
+                * be sent at once
+                */
+               if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = memdup_user(compat_ptr(tvps->props), tvps->num * 
sizeof(*tvp));
+               if (IS_ERR(tvp))
+                       return PTR_ERR(tvp);
+
+               /*
+                * Let's use our own copy of property cache, in order to
+                * avoid mangling with DTV zigzag logic, as drivers might
+                * return crap, if they don't check if the data is available
+                * before updating the properties cache.
+                */
+               if (fepriv->state != FESTATE_IDLE) {
+                       err = dtv_get_frontend(fe, &getp, NULL);
+                       if (err < 0) {
+                               kfree(tvp);
+                               return err;
+                       }
+               }
+               for (i = 0; i < tvps->num; i++) {
+                       err = dtv_property_process_get(
+                           fe, &getp, (struct dtv_property *)tvp + i, file);
+                       if (err < 0) {
+                               kfree(tvp);
+                               return err;
+                       }
+               }
+
+               if (copy_to_user((void __user *)compat_ptr(tvps->props), tvp,
+                                tvps->num * sizeof(struct 
compat_dtv_property))) {
+                       kfree(tvp);
+                       return -EFAULT;
+               }
+               kfree(tvp);
+       }
+
+       return err;
+}
+
 static long dvb_frontend_compat_ioctl(struct file *file, unsigned int cmd,
                                      unsigned long arg)
 {
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       int err;
+
+       if (cmd == COMPAT_FE_SET_PROPERTY || cmd == COMPAT_FE_GET_PROPERTY) {
+               if (down_interruptible(&fepriv->sem))
+                       return -ERESTARTSYS;
+
+               err = dvb_frontend_handle_compat_ioctl(file, cmd, arg);
+
+               up(&fepriv->sem);
+               return err;
+       }
+
        return dvb_frontend_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
 }
 #endif
-- 
2.17.1

Reply via email to