|
@@ -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
|