aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbmem.c')
-rw-r--r--drivers/video/fbmem.c174
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
1005static int 1005static long
1006fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 1006fb_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
1339out: 1370out:
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);