dvb-core: compatile with 32bit in 64bit kernel [1/1]
authorChuangcheng Peng <chuangcheng.peng@amlogic.com>
Fri, 7 Dec 2018 10:16:13 +0000 (18:16 +0800)
committerLuan Yuan <luan.yuan@amlogic.com>
Mon, 17 Dec 2018 06:55:24 +0000 (14:55 +0800)
PD#SWPL-3009

Problem:
32bit frontend app can't call ioctl in 64bit-kernel

Solution:
Add 32bit define in header and handle in dvb_frontend in 64bit-kernel

Verify:
Verify at android_p at R311

Change-Id: I63178803cfb1cf7d670e3c2b55f104e97f5afa63
Signed-off-by: Chuangcheng Peng <chuangcheng.peng@amlogic.com>
drivers/media/dvb-core/dvb_frontend.c
include/uapi/linux/dvb/frontend.h

index aa34713..e42024d 100644 (file)
@@ -1965,7 +1965,63 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
 
        return r;
 }
+static void dtv_property_32to64(struct dtv_property *dest,
+               struct dtv_property_32 *src)
+{
+       int i = 0;
+       long tmp = 0;
+
+       dest->cmd = src->cmd;
+//     printk("%s cmd:%d\n",__func__,dest->cmd);
+
+       for (i = 0; i < 3; i++)
+               dest->reserved[i] = src->reserved[i];
+
+       dest->u.data = src->u.data;
+       dest->u.st.len = src->u.st.len;
+
+       for (i = 0; i < MAX_DTV_STATS; i++) {
+               dest->u.st.stat[i].scale  = src->u.st.stat[i].scale;
+               dest->u.st.stat[i].uvalue = src->u.st.stat[i].uvalue;
+               dest->u.st.stat[i].svalue = src->u.st.stat[i].svalue;
+       }
+       for (i = 0; i < 32; i++)
+               dest->u.buffer.data[i] = src->u.buffer.data[i];
+       dest->u.buffer.len = src->u.buffer.len;
+       for (i = 0; i < 3; i++)
+               dest->u.buffer.reserved1[i] = src->u.buffer.reserved1[i];
+       tmp = (long)(src->u.buffer.reserved2);
+       dest->u.buffer.reserved2 = (void *)tmp;
+       dest->result = src->result;
+}
 
+static void dtv_property_64to32(struct dtv_property_32 *dest,
+               struct dtv_property *src)
+{
+       int i = 0;
+       long tmp = 0;
+
+       dest->cmd = src->cmd;
+//     printk("%s cmd:%d\n",__func__,dest->cmd);
+       for (i = 0; i < 3; i++)
+               dest->reserved[i] = src->reserved[i];
+       dest->u.data = src->u.data;
+//     printk("%s data:%d\n",__func__,dest->u.data);
+       dest->u.st.len = src->u.st.len;
+       for (i = 0; i < MAX_DTV_STATS; i++) {
+               dest->u.st.stat[i].scale  = src->u.st.stat[i].scale;
+               dest->u.st.stat[i].uvalue = src->u.st.stat[i].uvalue;
+               dest->u.st.stat[i].svalue = src->u.st.stat[i].svalue;
+       }
+       for (i = 0; i < 32; i++)
+               dest->u.buffer.data[i] = src->u.buffer.data[i];
+       dest->u.buffer.len = src->u.buffer.len;
+       for (i = 0; i < 3; i++)
+               dest->u.buffer.reserved1[i] = src->u.buffer.reserved1[i];
+       tmp = (long)(src->u.buffer.reserved2);
+       dest->u.buffer.reserved2 = (__u32)tmp;
+       dest->result = src->result;
+}
 static int dvb_frontend_ioctl(struct file *file,
                        unsigned int cmd, void *parg)
 {
@@ -1991,7 +2047,9 @@ static int dvb_frontend_ioctl(struct file *file,
                return -EPERM;
        }
 
-       if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+       if ((cmd == FE_SET_PROPERTY_32) || (cmd == FE_GET_PROPERTY_32)
+                       || (cmd == FE_SET_PROPERTY_64)
+                       || (cmd == FE_GET_PROPERTY_64))
                err = dvb_frontend_ioctl_properties(file, cmd, parg);
        else {
                c->state = DTV_UNDEFINED;
@@ -2012,12 +2070,45 @@ static int dvb_frontend_ioctl_properties(struct file *file,
        int err = 0;
 
        struct dtv_properties *tvps = parg;
+       struct dtv_properties_32 *tvps_32_tmp = parg;
+       struct dtv_properties tvps_tmp;
        struct dtv_property *tvp = NULL;
+       struct dtv_property_32 *tvp_32 = NULL;
        int i;
+       int prop = 0;
+       int convert = 0;
 
        dev_dbg(fe->dvb->device, "%s:\n", __func__);
+       if ((cmd == FE_SET_PROPERTY_32) || (cmd == FE_SET_PROPERTY_64)
+                       || (cmd == FE_GET_PROPERTY_32)
+                       || (cmd == FE_GET_PROPERTY_64)) {
+               prop = 1;
+
+               if ((cmd == FE_SET_PROPERTY_32) ||
+                               (cmd == FE_GET_PROPERTY_32)) {
+                       if (FE_SET_PROPERTY == FE_SET_PROPERTY_64)
+                               convert = 1;
+               }
+       }
+       if (prop) {
+               if (convert) {
+                       tvps_tmp.num  = tvps_32_tmp->num;
+       tvps_tmp.props = (struct dtv_property *)(long)(tvps_32_tmp->props);
+                       tvps = &tvps_tmp;
 
-       if (cmd == FE_SET_PROPERTY) {
+                       tvp_32 = memdup_user(tvps->props,
+                               tvps->num * sizeof(struct dtv_property_32));
+                       if (IS_ERR(tvp_32)) {
+                               err = -EFAULT;
+                               goto out;
+                       }
+               }
+       }
+#ifdef CONFIG_COMPAT
+       tvps->props = compat_ptr((unsigned long)tvps->props);
+#endif
+
+       if ((cmd == FE_SET_PROPERTY_32) || (cmd == FE_SET_PROPERTY_64)) {
                dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
                dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -2026,9 +2117,22 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
                        return -EINVAL;
 
-               tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
-               if (IS_ERR(tvp))
-                       return PTR_ERR(tvp);
+               if (convert) {
+                       tvp = kmalloc_array(tvps->num,
+                                       sizeof(*tvp), GFP_KERNEL);
+                       if (IS_ERR(tvp)) {
+                               err = -EFAULT;
+                               goto out;
+                       }
+
+                       for (i = 0; i < tvps->num; i++)
+                               dtv_property_32to64(tvp + i, tvp_32+i);
+               } else {
+                       tvp = memdup_user(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, tvp + i, file);
@@ -2040,7 +2144,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                if (c->state == DTV_TUNE)
                        dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
 
-       } else if (cmd == FE_GET_PROPERTY) {
+       } else if ((cmd == FE_GET_PROPERTY_32) || (cmd == FE_GET_PROPERTY_64)) {
                struct dtv_frontend_properties getp = fe->dtv_property_cache;
 
                dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
@@ -2051,9 +2155,20 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
                        return -EINVAL;
 
-               tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
-               if (IS_ERR(tvp))
-                       return PTR_ERR(tvp);
+               if (convert) {
+                       tvp = kmalloc_array(tvps->num,
+                                       sizeof(*tvp), GFP_KERNEL);
+                       if (IS_ERR(tvp))
+                               return PTR_ERR(tvp);
+
+                       for (i = 0; i < tvps->num; i++)
+                               dtv_property_32to64(tvp + i, tvp_32+i);
+               } else {
+                       tvp = memdup_user(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
@@ -2073,16 +2188,28 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        (tvp + i)->result = err;
                }
 
-               if (copy_to_user((void __user *)tvps->props, tvp,
-                                tvps->num * sizeof(struct dtv_property))) {
-                       err = -EFAULT;
-                       goto out;
-               }
+               if (convert) {
+                       for (i = 0; i < tvps->num; i++)
+                               dtv_property_64to32(tvp_32 + i,
+                                               (struct dtv_property *)(tvp+i));
 
+                       if (copy_to_user((void __user *)tvps->props, tvp_32,
+               tvps->num * sizeof(struct dtv_property_32))) {
+                               err = -EFAULT;
+                               goto out;
+                       }
+               } else {
+                       if (copy_to_user((void __user *)tvps->props, tvp,
+               tvps->num * sizeof(struct dtv_property))) {
+                               err = -EFAULT;
+                               goto out;
+                       }
+               }
        } else
                err = -EOPNOTSUPP;
 
 out:
+       kfree(tvp_32);
        kfree(tvp);
        return err;
 }
@@ -2663,24 +2790,14 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
 static long dvb_frontend_compat_ioctl(struct file *filp,
                        unsigned int cmd, unsigned long args)
 {
-       unsigned long ret;
-       struct dtv_properties tvps;
+       long ret;
+
 #ifdef CONFIG_COMPAT
        args  = (unsigned long)compat_ptr(args);
 #endif
-       if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) {
-               if (copy_from_user(&tvps, (void *)args,
-                       sizeof(struct dtv_properties)))
-                       return -EFAULT;
-#ifdef CONFIG_COMPAT
-               tvps.props = compat_ptr((unsigned long)tvps.props);
-#endif
-               if (copy_to_user((void *)args, (void *)&tvps,
-                       sizeof(struct dtv_properties)))
-                       return -EFAULT;
-       }
 
        ret = dvb_generic_ioctl(filp, cmd, args);
+
        return ret;
 }
 #endif
index e851a30..0b32aa3 100644 (file)
@@ -541,16 +541,38 @@ struct dtv_property {
                        __u32 reserved1[3];
                        void *reserved2;
                } buffer;
-#if 0
-#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+       } u;
+       int result;
+} __attribute__ ((packed));
+
+struct dtv_property_32 {
+       __u32 cmd;
+       __u32 reserved[3];
+       union {
+               __u32 data;
+               struct dtv_fe_stats st;
                struct {
                        __u8 data[32];
                        __u32 len;
                        __u32 reserved1[3];
-                       __u64 reserved;
-               } reserved;
-#endif
-#endif
+                       __u32 reserved2;
+               } buffer;
+       } u;
+       int result;
+} __attribute__ ((packed));
+
+struct dtv_property_64 {
+       __u32 cmd;
+       __u32 reserved[3];
+       union {
+               __u32 data;
+               struct dtv_fe_stats st;
+               struct {
+                       __u8 data[32];
+                       __u32 len;
+                       __u32 reserved1[3];
+                       __u64 reserved2;
+               } buffer;
        } u;
        int result;
 } __attribute__ ((packed));
@@ -560,14 +582,17 @@ struct dtv_property {
 
 struct dtv_properties {
        __u32 num;
-#if 0 && defined(CONFIG_AMLOGIC_DVB_COMPAT)
-       union {
-               struct dtv_property *props;
-               __u64                reserved;
-       };
-#else
        struct dtv_property *props;
-#endif
+};
+
+struct dtv_properties_32 {
+       __u32 num;
+       __u32 props;
+};
+
+struct dtv_properties_64 {
+       __u32 num;
+       __u64 props;
 };
 
 #if defined(__DVB_CORE__) || !defined (__KERNEL__)
@@ -722,6 +747,12 @@ struct dvbsx_blindscanevent {
 #define FE_SET_PROPERTY                   _IOW('o', 82, struct dtv_properties)
 #define FE_GET_PROPERTY                   _IOR('o', 83, struct dtv_properties)
 
+#define FE_SET_PROPERTY_32     _IOW('o', 82, struct dtv_properties_32)
+#define FE_GET_PROPERTY_32     _IOR('o', 83, struct dtv_properties_32)
+
+#define FE_SET_PROPERTY_64     _IOW('o', 82, struct dtv_properties_64)
+#define FE_GET_PROPERTY_64     _IOR('o', 83, struct dtv_properties_64)
+
 #ifdef CONFIG_AMLOGIC_DVB_COMPAT
 /*for atv*/
 struct tuner_status_s {