diff options
Diffstat (limited to 'drivers/video/fbmem.c')
-rw-r--r-- | drivers/video/fbmem.c | 174 |
1 files changed, 103 insertions, 71 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 217c5118ae9..cd5f20da738 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -1002,101 +1002,132 @@ fb_blank(struct fb_info *info, int blank) | |||
1002 | return ret; | 1002 | return ret; |
1003 | } | 1003 | } |
1004 | 1004 | ||
1005 | static int | 1005 | static long |
1006 | fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 1006 | fb_ioctl(struct file *file, unsigned int cmd, |
1007 | unsigned long arg) | 1007 | unsigned long arg) |
1008 | { | 1008 | { |
1009 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1009 | int fbidx = iminor(inode); | 1010 | int fbidx = iminor(inode); |
1010 | struct fb_info *info = registered_fb[fbidx]; | 1011 | struct fb_info *info; |
1011 | struct fb_ops *fb = info->fbops; | 1012 | struct fb_ops *fb; |
1012 | struct fb_var_screeninfo var; | 1013 | struct fb_var_screeninfo var; |
1013 | struct fb_fix_screeninfo fix; | 1014 | struct fb_fix_screeninfo fix; |
1014 | struct fb_con2fbmap con2fb; | 1015 | struct fb_con2fbmap con2fb; |
1015 | struct fb_cmap_user cmap; | 1016 | struct fb_cmap_user cmap; |
1016 | struct fb_event event; | 1017 | struct fb_event event; |
1017 | void __user *argp = (void __user *)arg; | 1018 | void __user *argp = (void __user *)arg; |
1018 | int i; | 1019 | long ret = 0; |
1019 | 1020 | ||
1020 | if (!fb) | 1021 | info = registered_fb[fbidx]; |
1022 | mutex_lock(&info->lock); | ||
1023 | fb = info->fbops; | ||
1024 | |||
1025 | if (!fb) { | ||
1026 | mutex_unlock(&info->lock); | ||
1021 | return -ENODEV; | 1027 | return -ENODEV; |
1028 | } | ||
1022 | switch (cmd) { | 1029 | switch (cmd) { |
1023 | case FBIOGET_VSCREENINFO: | 1030 | case FBIOGET_VSCREENINFO: |
1024 | return copy_to_user(argp, &info->var, | 1031 | ret = copy_to_user(argp, &info->var, |
1025 | sizeof(var)) ? -EFAULT : 0; | 1032 | sizeof(var)) ? -EFAULT : 0; |
1033 | break; | ||
1026 | case FBIOPUT_VSCREENINFO: | 1034 | case FBIOPUT_VSCREENINFO: |
1027 | if (copy_from_user(&var, argp, sizeof(var))) | 1035 | if (copy_from_user(&var, argp, sizeof(var))) { |
1028 | return -EFAULT; | 1036 | ret = -EFAULT; |
1037 | break; | ||
1038 | } | ||
1029 | acquire_console_sem(); | 1039 | acquire_console_sem(); |
1030 | info->flags |= FBINFO_MISC_USEREVENT; | 1040 | info->flags |= FBINFO_MISC_USEREVENT; |
1031 | i = fb_set_var(info, &var); | 1041 | ret = fb_set_var(info, &var); |
1032 | info->flags &= ~FBINFO_MISC_USEREVENT; | 1042 | info->flags &= ~FBINFO_MISC_USEREVENT; |
1033 | release_console_sem(); | 1043 | release_console_sem(); |
1034 | if (i) return i; | 1044 | if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) |
1035 | if (copy_to_user(argp, &var, sizeof(var))) | 1045 | ret = -EFAULT; |
1036 | return -EFAULT; | 1046 | break; |
1037 | return 0; | ||
1038 | case FBIOGET_FSCREENINFO: | 1047 | case FBIOGET_FSCREENINFO: |
1039 | return copy_to_user(argp, &info->fix, | 1048 | ret = copy_to_user(argp, &info->fix, |
1040 | sizeof(fix)) ? -EFAULT : 0; | 1049 | sizeof(fix)) ? -EFAULT : 0; |
1050 | break; | ||
1041 | case FBIOPUTCMAP: | 1051 | case FBIOPUTCMAP: |
1042 | if (copy_from_user(&cmap, argp, sizeof(cmap))) | 1052 | if (copy_from_user(&cmap, argp, sizeof(cmap))) |
1043 | return -EFAULT; | 1053 | ret = -EFAULT; |
1044 | return (fb_set_user_cmap(&cmap, info)); | 1054 | else |
1055 | ret = fb_set_user_cmap(&cmap, info); | ||
1056 | break; | ||
1045 | case FBIOGETCMAP: | 1057 | case FBIOGETCMAP: |
1046 | if (copy_from_user(&cmap, argp, sizeof(cmap))) | 1058 | if (copy_from_user(&cmap, argp, sizeof(cmap))) |
1047 | return -EFAULT; | 1059 | ret = -EFAULT; |
1048 | return fb_cmap_to_user(&info->cmap, &cmap); | 1060 | else |
1061 | ret = fb_cmap_to_user(&info->cmap, &cmap); | ||
1062 | break; | ||
1049 | case FBIOPAN_DISPLAY: | 1063 | case FBIOPAN_DISPLAY: |
1050 | if (copy_from_user(&var, argp, sizeof(var))) | 1064 | if (copy_from_user(&var, argp, sizeof(var))) { |
1051 | return -EFAULT; | 1065 | ret = -EFAULT; |
1066 | break; | ||
1067 | } | ||
1052 | acquire_console_sem(); | 1068 | acquire_console_sem(); |
1053 | i = fb_pan_display(info, &var); | 1069 | ret = fb_pan_display(info, &var); |
1054 | release_console_sem(); | 1070 | release_console_sem(); |
1055 | if (i) | 1071 | if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) |
1056 | return i; | 1072 | ret = -EFAULT; |
1057 | if (copy_to_user(argp, &var, sizeof(var))) | 1073 | break; |
1058 | return -EFAULT; | ||
1059 | return 0; | ||
1060 | case FBIO_CURSOR: | 1074 | case FBIO_CURSOR: |
1061 | return -EINVAL; | 1075 | ret = -EINVAL; |
1076 | break; | ||
1062 | case FBIOGET_CON2FBMAP: | 1077 | case FBIOGET_CON2FBMAP: |
1063 | if (copy_from_user(&con2fb, argp, sizeof(con2fb))) | 1078 | if (copy_from_user(&con2fb, argp, sizeof(con2fb))) |
1064 | return -EFAULT; | 1079 | ret = -EFAULT; |
1065 | if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) | 1080 | else if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) |
1066 | return -EINVAL; | 1081 | ret = -EINVAL; |
1067 | con2fb.framebuffer = -1; | 1082 | else { |
1068 | event.info = info; | 1083 | con2fb.framebuffer = -1; |
1069 | event.data = &con2fb; | 1084 | event.info = info; |
1070 | fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); | 1085 | event.data = &con2fb; |
1071 | return copy_to_user(argp, &con2fb, | 1086 | fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, |
1087 | &event); | ||
1088 | ret = copy_to_user(argp, &con2fb, | ||
1072 | sizeof(con2fb)) ? -EFAULT : 0; | 1089 | sizeof(con2fb)) ? -EFAULT : 0; |
1090 | } | ||
1091 | break; | ||
1073 | case FBIOPUT_CON2FBMAP: | 1092 | case FBIOPUT_CON2FBMAP: |
1074 | if (copy_from_user(&con2fb, argp, sizeof(con2fb))) | 1093 | if (copy_from_user(&con2fb, argp, sizeof(con2fb))) { |
1075 | return - EFAULT; | 1094 | ret = -EFAULT; |
1076 | if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) | 1095 | break; |
1077 | return -EINVAL; | 1096 | } |
1078 | if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) | 1097 | if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) { |
1079 | return -EINVAL; | 1098 | ret = -EINVAL; |
1080 | if (!registered_fb[con2fb.framebuffer]) | 1099 | break; |
1081 | request_module("fb%d", con2fb.framebuffer); | 1100 | } |
1101 | if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) { | ||
1102 | ret = -EINVAL; | ||
1103 | break; | ||
1104 | } | ||
1082 | if (!registered_fb[con2fb.framebuffer]) | 1105 | if (!registered_fb[con2fb.framebuffer]) |
1083 | return -EINVAL; | 1106 | request_module("fb%d", con2fb.framebuffer); |
1107 | if (!registered_fb[con2fb.framebuffer]) { | ||
1108 | ret = -EINVAL; | ||
1109 | break; | ||
1110 | } | ||
1084 | event.info = info; | 1111 | event.info = info; |
1085 | event.data = &con2fb; | 1112 | event.data = &con2fb; |
1086 | return fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, | 1113 | ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, |
1087 | &event); | 1114 | &event); |
1115 | break; | ||
1088 | case FBIOBLANK: | 1116 | case FBIOBLANK: |
1089 | acquire_console_sem(); | 1117 | acquire_console_sem(); |
1090 | info->flags |= FBINFO_MISC_USEREVENT; | 1118 | info->flags |= FBINFO_MISC_USEREVENT; |
1091 | i = fb_blank(info, arg); | 1119 | ret = fb_blank(info, arg); |
1092 | info->flags &= ~FBINFO_MISC_USEREVENT; | 1120 | info->flags &= ~FBINFO_MISC_USEREVENT; |
1093 | release_console_sem(); | 1121 | release_console_sem(); |
1094 | return i; | 1122 | break;; |
1095 | default: | 1123 | default: |
1096 | if (fb->fb_ioctl == NULL) | 1124 | if (fb->fb_ioctl == NULL) |
1097 | return -EINVAL; | 1125 | ret = -ENOTTY; |
1098 | return fb->fb_ioctl(info, cmd, arg); | 1126 | else |
1127 | ret = fb->fb_ioctl(info, cmd, arg); | ||
1099 | } | 1128 | } |
1129 | mutex_unlock(&info->lock); | ||
1130 | return ret; | ||
1100 | } | 1131 | } |
1101 | 1132 | ||
1102 | #ifdef CONFIG_COMPAT | 1133 | #ifdef CONFIG_COMPAT |
@@ -1150,7 +1181,7 @@ static int fb_getput_cmap(struct inode *inode, struct file *file, | |||
1150 | put_user(compat_ptr(data), &cmap->transp)) | 1181 | put_user(compat_ptr(data), &cmap->transp)) |
1151 | return -EFAULT; | 1182 | return -EFAULT; |
1152 | 1183 | ||
1153 | err = fb_ioctl(inode, file, cmd, (unsigned long) cmap); | 1184 | err = fb_ioctl(file, cmd, (unsigned long) cmap); |
1154 | 1185 | ||
1155 | if (!err) { | 1186 | if (!err) { |
1156 | if (copy_in_user(&cmap32->start, | 1187 | if (copy_in_user(&cmap32->start, |
@@ -1204,7 +1235,7 @@ static int fb_get_fscreeninfo(struct inode *inode, struct file *file, | |||
1204 | 1235 | ||
1205 | old_fs = get_fs(); | 1236 | old_fs = get_fs(); |
1206 | set_fs(KERNEL_DS); | 1237 | set_fs(KERNEL_DS); |
1207 | err = fb_ioctl(inode, file, cmd, (unsigned long) &fix); | 1238 | err = fb_ioctl(file, cmd, (unsigned long) &fix); |
1208 | set_fs(old_fs); | 1239 | set_fs(old_fs); |
1209 | 1240 | ||
1210 | if (!err) | 1241 | if (!err) |
@@ -1222,7 +1253,7 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1222 | struct fb_ops *fb = info->fbops; | 1253 | struct fb_ops *fb = info->fbops; |
1223 | long ret = -ENOIOCTLCMD; | 1254 | long ret = -ENOIOCTLCMD; |
1224 | 1255 | ||
1225 | lock_kernel(); | 1256 | mutex_lock(&info->lock); |
1226 | switch(cmd) { | 1257 | switch(cmd) { |
1227 | case FBIOGET_VSCREENINFO: | 1258 | case FBIOGET_VSCREENINFO: |
1228 | case FBIOPUT_VSCREENINFO: | 1259 | case FBIOPUT_VSCREENINFO: |
@@ -1231,7 +1262,7 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1231 | case FBIOPUT_CON2FBMAP: | 1262 | case FBIOPUT_CON2FBMAP: |
1232 | arg = (unsigned long) compat_ptr(arg); | 1263 | arg = (unsigned long) compat_ptr(arg); |
1233 | case FBIOBLANK: | 1264 | case FBIOBLANK: |
1234 | ret = fb_ioctl(inode, file, cmd, arg); | 1265 | ret = fb_ioctl(file, cmd, arg); |
1235 | break; | 1266 | break; |
1236 | 1267 | ||
1237 | case FBIOGET_FSCREENINFO: | 1268 | case FBIOGET_FSCREENINFO: |
@@ -1248,7 +1279,7 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1248 | ret = fb->fb_compat_ioctl(info, cmd, arg); | 1279 | ret = fb->fb_compat_ioctl(info, cmd, arg); |
1249 | break; | 1280 | break; |
1250 | } | 1281 | } |
1251 | unlock_kernel(); | 1282 | mutex_unlock(&info->lock); |
1252 | return ret; | 1283 | return ret; |
1253 | } | 1284 | } |
1254 | #endif | 1285 | #endif |
@@ -1270,13 +1301,13 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) | |||
1270 | return -ENODEV; | 1301 | return -ENODEV; |
1271 | if (fb->fb_mmap) { | 1302 | if (fb->fb_mmap) { |
1272 | int res; | 1303 | int res; |
1273 | lock_kernel(); | 1304 | mutex_lock(&info->lock); |
1274 | res = fb->fb_mmap(info, vma); | 1305 | res = fb->fb_mmap(info, vma); |
1275 | unlock_kernel(); | 1306 | mutex_unlock(&info->lock); |
1276 | return res; | 1307 | return res; |
1277 | } | 1308 | } |
1278 | 1309 | ||
1279 | lock_kernel(); | 1310 | mutex_lock(&info->lock); |
1280 | 1311 | ||
1281 | /* frame buffer memory */ | 1312 | /* frame buffer memory */ |
1282 | start = info->fix.smem_start; | 1313 | start = info->fix.smem_start; |
@@ -1285,13 +1316,13 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) | |||
1285 | /* memory mapped io */ | 1316 | /* memory mapped io */ |
1286 | off -= len; | 1317 | off -= len; |
1287 | if (info->var.accel_flags) { | 1318 | if (info->var.accel_flags) { |
1288 | unlock_kernel(); | 1319 | mutex_unlock(&info->lock); |
1289 | return -EINVAL; | 1320 | return -EINVAL; |
1290 | } | 1321 | } |
1291 | start = info->fix.mmio_start; | 1322 | start = info->fix.mmio_start; |
1292 | len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); | 1323 | len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); |
1293 | } | 1324 | } |
1294 | unlock_kernel(); | 1325 | mutex_unlock(&info->lock); |
1295 | start &= PAGE_MASK; | 1326 | start &= PAGE_MASK; |
1296 | if ((vma->vm_end - vma->vm_start + off) > len) | 1327 | if ((vma->vm_end - vma->vm_start + off) > len) |
1297 | return -EINVAL; | 1328 | return -EINVAL; |
@@ -1315,13 +1346,13 @@ fb_open(struct inode *inode, struct file *file) | |||
1315 | 1346 | ||
1316 | if (fbidx >= FB_MAX) | 1347 | if (fbidx >= FB_MAX) |
1317 | return -ENODEV; | 1348 | return -ENODEV; |
1318 | lock_kernel(); | 1349 | info = registered_fb[fbidx]; |
1319 | if (!(info = registered_fb[fbidx])) | 1350 | if (!info) |
1320 | request_module("fb%d", fbidx); | 1351 | request_module("fb%d", fbidx); |
1321 | if (!(info = registered_fb[fbidx])) { | 1352 | info = registered_fb[fbidx]; |
1322 | res = -ENODEV; | 1353 | if (!info) |
1323 | goto out; | 1354 | return -ENODEV; |
1324 | } | 1355 | mutex_lock(&info->lock); |
1325 | if (!try_module_get(info->fbops->owner)) { | 1356 | if (!try_module_get(info->fbops->owner)) { |
1326 | res = -ENODEV; | 1357 | res = -ENODEV; |
1327 | goto out; | 1358 | goto out; |
@@ -1337,7 +1368,7 @@ fb_open(struct inode *inode, struct file *file) | |||
1337 | fb_deferred_io_open(info, inode, file); | 1368 | fb_deferred_io_open(info, inode, file); |
1338 | #endif | 1369 | #endif |
1339 | out: | 1370 | out: |
1340 | unlock_kernel(); | 1371 | mutex_unlock(&info->lock); |
1341 | return res; | 1372 | return res; |
1342 | } | 1373 | } |
1343 | 1374 | ||
@@ -1346,11 +1377,11 @@ fb_release(struct inode *inode, struct file *file) | |||
1346 | { | 1377 | { |
1347 | struct fb_info * const info = file->private_data; | 1378 | struct fb_info * const info = file->private_data; |
1348 | 1379 | ||
1349 | lock_kernel(); | 1380 | mutex_lock(&info->lock); |
1350 | if (info->fbops->fb_release) | 1381 | if (info->fbops->fb_release) |
1351 | info->fbops->fb_release(info,1); | 1382 | info->fbops->fb_release(info,1); |
1352 | module_put(info->fbops->owner); | 1383 | module_put(info->fbops->owner); |
1353 | unlock_kernel(); | 1384 | mutex_unlock(&info->lock); |
1354 | return 0; | 1385 | return 0; |
1355 | } | 1386 | } |
1356 | 1387 | ||
@@ -1358,7 +1389,7 @@ static const struct file_operations fb_fops = { | |||
1358 | .owner = THIS_MODULE, | 1389 | .owner = THIS_MODULE, |
1359 | .read = fb_read, | 1390 | .read = fb_read, |
1360 | .write = fb_write, | 1391 | .write = fb_write, |
1361 | .ioctl = fb_ioctl, | 1392 | .unlocked_ioctl = fb_ioctl, |
1362 | #ifdef CONFIG_COMPAT | 1393 | #ifdef CONFIG_COMPAT |
1363 | .compat_ioctl = fb_compat_ioctl, | 1394 | .compat_ioctl = fb_compat_ioctl, |
1364 | #endif | 1395 | #endif |
@@ -1429,6 +1460,7 @@ register_framebuffer(struct fb_info *fb_info) | |||
1429 | if (!registered_fb[i]) | 1460 | if (!registered_fb[i]) |
1430 | break; | 1461 | break; |
1431 | fb_info->node = i; | 1462 | fb_info->node = i; |
1463 | mutex_init(&fb_info->lock); | ||
1432 | 1464 | ||
1433 | fb_info->dev = device_create(fb_class, fb_info->device, | 1465 | fb_info->dev = device_create(fb_class, fb_info->device, |
1434 | MKDEV(FB_MAJOR, i), NULL, "fb%d", i); | 1466 | MKDEV(FB_MAJOR, i), NULL, "fb%d", i); |