media: dvb_frontend: Add commands implementation for compat ioct
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.shin@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
parent
c2dfd2276c
commit
18192a77f0
@ -1979,9 +1979,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 = ∝
|
||||
|
||||
/*
|
||||
* 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 = ∝
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
Loading…
Reference in New Issue
Block a user