From 93f63edd13a85e1a681de86774f52fb7b740a380 Mon Sep 17 00:00:00 2001 From: Chuangcheng Peng Date: Fri, 7 Dec 2018 18:16:13 +0800 Subject: [PATCH] dvb-core: compatile with 32bit in 64bit kernel [1/1] 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 --- drivers/media/dvb-core/dvb_frontend.c | 171 ++++++++++++++++++++++---- include/uapi/linux/dvb/frontend.h | 57 +++++++-- 2 files changed, 188 insertions(+), 40 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index aa34713b44a4..e42024d68152 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -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 diff --git a/include/uapi/linux/dvb/frontend.h b/include/uapi/linux/dvb/frontend.h index e851a304aee6..0b32aa331dbd 100644 --- a/include/uapi/linux/dvb/frontend.h +++ b/include/uapi/linux/dvb/frontend.h @@ -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 { -- 2.20.1