aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-12-18 18:45:39 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-03-19 13:07:01 -0400
commit1a5e4c867c611ed17db837f8f900b44c72990cc4 (patch)
tree736d1bc0975bcbaaba809fc9e2e73a87b48190d0 /drivers
parenta3ec69b707718cb95317d1b783560210487c55a8 (diff)
[media] uvcvideo: Implement compat_ioctl32 for custom ioctls
Support 32-bit/64-bit compatibility for the the UVCIOC_ ioctls. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index f09ee8b2ea5..ff2cdddf9bc 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -11,6 +11,7 @@
11 * 11 *
12 */ 12 */
13 13
14#include <linux/compat.h>
14#include <linux/kernel.h> 15#include <linux/kernel.h>
15#include <linux/version.h> 16#include <linux/version.h>
16#include <linux/list.h> 17#include <linux/list.h>
@@ -1030,6 +1031,207 @@ static long uvc_v4l2_ioctl(struct file *file,
1030 return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); 1031 return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
1031} 1032}
1032 1033
1034#ifdef CONFIG_COMPAT
1035struct uvc_xu_control_mapping32 {
1036 __u32 id;
1037 __u8 name[32];
1038 __u8 entity[16];
1039 __u8 selector;
1040
1041 __u8 size;
1042 __u8 offset;
1043 __u32 v4l2_type;
1044 __u32 data_type;
1045
1046 compat_caddr_t menu_info;
1047 __u32 menu_count;
1048
1049 __u32 reserved[4];
1050};
1051
1052static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
1053 const struct uvc_xu_control_mapping32 __user *up)
1054{
1055 struct uvc_menu_info __user *umenus;
1056 struct uvc_menu_info __user *kmenus;
1057 compat_caddr_t p;
1058
1059 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
1060 __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) ||
1061 __get_user(kp->menu_count, &up->menu_count))
1062 return -EFAULT;
1063
1064 memset(kp->reserved, 0, sizeof(kp->reserved));
1065
1066 if (kp->menu_count == 0) {
1067 kp->menu_info = NULL;
1068 return 0;
1069 }
1070
1071 if (__get_user(p, &up->menu_info))
1072 return -EFAULT;
1073 umenus = compat_ptr(p);
1074 if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus)))
1075 return -EFAULT;
1076
1077 kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus));
1078 if (kmenus == NULL)
1079 return -EFAULT;
1080 kp->menu_info = kmenus;
1081
1082 if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus)))
1083 return -EFAULT;
1084
1085 return 0;
1086}
1087
1088static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
1089 struct uvc_xu_control_mapping32 __user *up)
1090{
1091 struct uvc_menu_info __user *umenus;
1092 struct uvc_menu_info __user *kmenus = kp->menu_info;
1093 compat_caddr_t p;
1094
1095 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
1096 __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) ||
1097 __put_user(kp->menu_count, &up->menu_count))
1098 return -EFAULT;
1099
1100 __clear_user(up->reserved, sizeof(up->reserved));
1101
1102 if (kp->menu_count == 0)
1103 return 0;
1104
1105 if (get_user(p, &up->menu_info))
1106 return -EFAULT;
1107 umenus = compat_ptr(p);
1108 if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus)))
1109 return -EFAULT;
1110
1111 if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus)))
1112 return -EFAULT;
1113
1114 return 0;
1115}
1116
1117struct uvc_xu_control_query32 {
1118 __u8 unit;
1119 __u8 selector;
1120 __u8 query;
1121 __u16 size;
1122 compat_caddr_t data;
1123};
1124
1125static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
1126 const struct uvc_xu_control_query32 __user *up)
1127{
1128 u8 __user *udata;
1129 u8 __user *kdata;
1130 compat_caddr_t p;
1131
1132 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
1133 __copy_from_user(kp, up, offsetof(typeof(*up), data)))
1134 return -EFAULT;
1135
1136 if (kp->size == 0) {
1137 kp->data = NULL;
1138 return 0;
1139 }
1140
1141 if (__get_user(p, &up->data))
1142 return -EFAULT;
1143 udata = compat_ptr(p);
1144 if (!access_ok(VERIFY_READ, udata, kp->size))
1145 return -EFAULT;
1146
1147 kdata = compat_alloc_user_space(kp->size);
1148 if (kdata == NULL)
1149 return -EFAULT;
1150 kp->data = kdata;
1151
1152 if (copy_in_user(kdata, udata, kp->size))
1153 return -EFAULT;
1154
1155 return 0;
1156}
1157
1158static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
1159 struct uvc_xu_control_query32 __user *up)
1160{
1161 u8 __user *udata;
1162 u8 __user *kdata = kp->data;
1163 compat_caddr_t p;
1164
1165 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
1166 __copy_to_user(up, kp, offsetof(typeof(*up), data)))
1167 return -EFAULT;
1168
1169 if (kp->size == 0)
1170 return 0;
1171
1172 if (get_user(p, &up->data))
1173 return -EFAULT;
1174 udata = compat_ptr(p);
1175 if (!access_ok(VERIFY_READ, udata, kp->size))
1176 return -EFAULT;
1177
1178 if (copy_in_user(udata, kdata, kp->size))
1179 return -EFAULT;
1180
1181 return 0;
1182}
1183
1184#define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32)
1185#define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32)
1186
1187static long uvc_v4l2_compat_ioctl32(struct file *file,
1188 unsigned int cmd, unsigned long arg)
1189{
1190 union {
1191 struct uvc_xu_control_mapping xmap;
1192 struct uvc_xu_control_query xqry;
1193 } karg;
1194 void __user *up = compat_ptr(arg);
1195 mm_segment_t old_fs;
1196 long ret;
1197
1198 switch (cmd) {
1199 case UVCIOC_CTRL_MAP32:
1200 cmd = UVCIOC_CTRL_MAP;
1201 ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
1202 break;
1203
1204 case UVCIOC_CTRL_QUERY32:
1205 cmd = UVCIOC_CTRL_QUERY;
1206 ret = uvc_v4l2_get_xu_query(&karg.xqry, up);
1207 break;
1208
1209 default:
1210 return -ENOIOCTLCMD;
1211 }
1212
1213 old_fs = get_fs();
1214 set_fs(KERNEL_DS);
1215 ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg);
1216 set_fs(old_fs);
1217
1218 if (ret < 0)
1219 return ret;
1220
1221 switch (cmd) {
1222 case UVCIOC_CTRL_MAP:
1223 ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
1224 break;
1225
1226 case UVCIOC_CTRL_QUERY:
1227 ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
1228 break;
1229 }
1230
1231 return ret;
1232}
1233#endif
1234
1033static ssize_t uvc_v4l2_read(struct file *file, char __user *data, 1235static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
1034 size_t count, loff_t *ppos) 1236 size_t count, loff_t *ppos)
1035{ 1237{
@@ -1076,6 +1278,9 @@ const struct v4l2_file_operations uvc_fops = {
1076 .open = uvc_v4l2_open, 1278 .open = uvc_v4l2_open,
1077 .release = uvc_v4l2_release, 1279 .release = uvc_v4l2_release,
1078 .unlocked_ioctl = uvc_v4l2_ioctl, 1280 .unlocked_ioctl = uvc_v4l2_ioctl,
1281#ifdef CONFIG_COMPAT
1282 .compat_ioctl32 = uvc_v4l2_compat_ioctl32,
1283#endif
1079 .read = uvc_v4l2_read, 1284 .read = uvc_v4l2_read,
1080 .mmap = uvc_v4l2_mmap, 1285 .mmap = uvc_v4l2_mmap,
1081 .poll = uvc_v4l2_poll, 1286 .poll = uvc_v4l2_poll,