hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/video/fbdev/core/fbmem.c
....@@ -28,13 +28,13 @@
2828 #include <linux/seq_file.h>
2929 #include <linux/console.h>
3030 #include <linux/kmod.h>
31
-#include <linux/dma-buf.h>
3231 #include <linux/err.h>
3332 #include <linux/device.h>
3433 #include <linux/efi.h>
3534 #include <linux/fb.h>
3635 #include <linux/fbcon.h>
3736 #include <linux/mem_encrypt.h>
37
+#include <linux/pci.h>
3838
3939 #include <asm/fb.h>
4040
....@@ -52,6 +52,10 @@
5252
5353 int num_registered_fb __read_mostly;
5454 EXPORT_SYMBOL(num_registered_fb);
55
+
56
+bool fb_center_logo __read_mostly;
57
+
58
+int fb_logo_count __read_mostly = -1;
5559
5660 static struct fb_info *get_fb_info(unsigned int idx)
5761 {
....@@ -76,17 +80,6 @@
7680 if (fb_info->fbops->fb_destroy)
7781 fb_info->fbops->fb_destroy(fb_info);
7882 }
79
-
80
-int lock_fb_info(struct fb_info *info)
81
-{
82
- mutex_lock(&info->lock);
83
- if (!info->fbops) {
84
- mutex_unlock(&info->lock);
85
- return 0;
86
- }
87
- return 1;
88
-}
89
-EXPORT_SYMBOL(lock_fb_info);
9083
9184 /*
9285 * Helpers
....@@ -509,8 +502,24 @@
509502 fb_set_logo(info, logo, logo_new, fb_logo.depth);
510503 }
511504
512
- image.dx = 0;
513
- image.dy = y;
505
+ if (fb_center_logo) {
506
+ int xres = info->var.xres;
507
+ int yres = info->var.yres;
508
+
509
+ if (rotate == FB_ROTATE_CW || rotate == FB_ROTATE_CCW) {
510
+ xres = info->var.yres;
511
+ yres = info->var.xres;
512
+ }
513
+
514
+ while (n && (n * (logo->width + 8) - 8 > xres))
515
+ --n;
516
+ image.dx = (xres - (n * (logo->width + 8) - 8)) / 2;
517
+ image.dy = y ?: (yres - logo->height) / 2;
518
+ } else {
519
+ image.dx = 0;
520
+ image.dy = y;
521
+ }
522
+
514523 image.width = logo->width;
515524 image.height = logo->height;
516525
....@@ -528,7 +537,7 @@
528537 info->pseudo_palette = saved_pseudo_palette;
529538 kfree(logo_new);
530539 kfree(logo_rotate);
531
- return logo->height;
540
+ return image.dy + logo->height;
532541 }
533542
534543
....@@ -580,8 +589,8 @@
580589 unsigned int i;
581590
582591 for (i = 0; i < fb_logo_ex_num; i++)
583
- y += fb_show_logo_line(info, rotate,
584
- fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
592
+ y = fb_show_logo_line(info, rotate,
593
+ fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
585594
586595 return y;
587596 }
....@@ -607,11 +616,12 @@
607616 {
608617 int depth = fb_get_color_depth(&info->var, &info->fix);
609618 unsigned int yres;
619
+ int height;
610620
611621 memset(&fb_logo, 0, sizeof(struct logo_data));
612622
613623 if (info->flags & FBINFO_MISC_TILEBLITTING ||
614
- info->fbops->owner)
624
+ info->fbops->owner || !fb_logo_count)
615625 return 0;
616626
617627 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
....@@ -653,30 +663,38 @@
653663 fb_logo.depth = 1;
654664
655665
656
- if (fb_logo.depth > 4 && depth > 4) {
657
- switch (info->fix.visual) {
658
- case FB_VISUAL_TRUECOLOR:
659
- fb_logo.needs_truepalette = 1;
660
- break;
661
- case FB_VISUAL_DIRECTCOLOR:
662
- fb_logo.needs_directpalette = 1;
663
- fb_logo.needs_cmapreset = 1;
664
- break;
665
- case FB_VISUAL_PSEUDOCOLOR:
666
- fb_logo.needs_cmapreset = 1;
667
- break;
668
- }
669
- }
666
+ if (fb_logo.depth > 4 && depth > 4) {
667
+ switch (info->fix.visual) {
668
+ case FB_VISUAL_TRUECOLOR:
669
+ fb_logo.needs_truepalette = 1;
670
+ break;
671
+ case FB_VISUAL_DIRECTCOLOR:
672
+ fb_logo.needs_directpalette = 1;
673
+ fb_logo.needs_cmapreset = 1;
674
+ break;
675
+ case FB_VISUAL_PSEUDOCOLOR:
676
+ fb_logo.needs_cmapreset = 1;
677
+ break;
678
+ }
679
+ }
670680
671
- return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
681
+ height = fb_logo.logo->height;
682
+ if (fb_center_logo)
683
+ height += (yres - fb_logo.logo->height) / 2;
684
+
685
+ return fb_prepare_extra_logos(info, height, yres);
672686 }
673687
674688 int fb_show_logo(struct fb_info *info, int rotate)
675689 {
690
+ unsigned int count;
676691 int y;
677692
678
- y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
679
- num_online_cpus());
693
+ if (!fb_logo_count)
694
+ return 0;
695
+
696
+ count = fb_logo_count < 0 ? num_online_cpus() : fb_logo_count;
697
+ y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count);
680698 y = fb_show_extra_logos(info, y, rotate);
681699
682700 return y;
....@@ -759,7 +777,7 @@
759777
760778 if (info->fbops->fb_read)
761779 return info->fbops->fb_read(info, buf, count, ppos);
762
-
780
+
763781 total_size = info->screen_size;
764782
765783 if (total_size == 0)
....@@ -824,7 +842,7 @@
824842
825843 if (info->fbops->fb_write)
826844 return info->fbops->fb_write(info, buf, count, ppos);
827
-
845
+
828846 total_size = info->screen_size;
829847
830848 if (total_size == 0)
....@@ -919,16 +937,13 @@
919937 static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
920938 u32 activate)
921939 {
922
- struct fb_event event;
923940 struct fb_blit_caps caps, fbcaps;
924941 int err = 0;
925942
926943 memset(&caps, 0, sizeof(caps));
927944 memset(&fbcaps, 0, sizeof(fbcaps));
928945 caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
929
- event.info = info;
930
- event.data = &caps;
931
- fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
946
+ fbcon_get_requirement(info, &caps);
932947 info->fbops->fb_get_caps(info, &fbcaps, var);
933948
934949 if (((fbcaps.x ^ caps.x) & caps.x) ||
....@@ -942,8 +957,12 @@
942957 int
943958 fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
944959 {
945
- int flags = info->flags;
946960 int ret = 0;
961
+ u32 activate;
962
+ struct fb_var_screeninfo old_var;
963
+ struct fb_videomode mode;
964
+ struct fb_event event;
965
+ u32 unused;
947966
948967 if (var->activate & FB_ACTIVATE_INV_MODE) {
949968 struct fb_videomode mode1, mode2;
....@@ -952,182 +971,144 @@
952971 fb_var_to_videomode(&mode2, &info->var);
953972 /* make sure we don't delete the videomode of current var */
954973 ret = fb_mode_is_equal(&mode1, &mode2);
955
-
956974 if (!ret) {
957
- struct fb_event event;
958
-
959
- event.info = info;
960
- event.data = &mode1;
961
- ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
975
+ ret = fbcon_mode_deleted(info, &mode1);
976
+ if (!ret)
977
+ fb_delete_videomode(&mode1, &info->modelist);
962978 }
963979
964
- if (!ret)
965
- fb_delete_videomode(&mode1, &info->modelist);
966
-
967
-
968
- ret = (ret) ? -EINVAL : 0;
969
- goto done;
980
+ return ret ? -EINVAL : 0;
970981 }
971982
972
- if ((var->activate & FB_ACTIVATE_FORCE) ||
973
- memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
974
- u32 activate = var->activate;
975
- u32 unused;
983
+ if (!(var->activate & FB_ACTIVATE_FORCE) &&
984
+ !memcmp(&info->var, var, sizeof(struct fb_var_screeninfo)))
985
+ return 0;
976986
977
- /* When using FOURCC mode, make sure the red, green, blue and
978
- * transp fields are set to 0.
979
- */
980
- if ((info->fix.capabilities & FB_CAP_FOURCC) &&
981
- var->grayscale > 1) {
982
- if (var->red.offset || var->green.offset ||
983
- var->blue.offset || var->transp.offset ||
984
- var->red.length || var->green.length ||
985
- var->blue.length || var->transp.length ||
986
- var->red.msb_right || var->green.msb_right ||
987
- var->blue.msb_right || var->transp.msb_right)
988
- return -EINVAL;
989
- }
987
+ activate = var->activate;
990988
991
- if (!info->fbops->fb_check_var) {
992
- *var = info->var;
993
- goto done;
994
- }
995
-
996
- /* bitfill_aligned() assumes that it's at least 8x8 */
997
- if (var->xres < 8 || var->yres < 8)
989
+ /* When using FOURCC mode, make sure the red, green, blue and
990
+ * transp fields are set to 0.
991
+ */
992
+ if ((info->fix.capabilities & FB_CAP_FOURCC) &&
993
+ var->grayscale > 1) {
994
+ if (var->red.offset || var->green.offset ||
995
+ var->blue.offset || var->transp.offset ||
996
+ var->red.length || var->green.length ||
997
+ var->blue.length || var->transp.length ||
998
+ var->red.msb_right || var->green.msb_right ||
999
+ var->blue.msb_right || var->transp.msb_right)
9981000 return -EINVAL;
1001
+ }
9991002
1000
- /* Too huge resolution causes multiplication overflow. */
1001
- if (check_mul_overflow(var->xres, var->yres, &unused) ||
1002
- check_mul_overflow(var->xres_virtual, var->yres_virtual, &unused))
1003
- return -EINVAL;
1003
+ if (!info->fbops->fb_check_var) {
1004
+ *var = info->var;
1005
+ return 0;
1006
+ }
10041007
1005
- ret = info->fbops->fb_check_var(var, info);
1008
+ /* bitfill_aligned() assumes that it's at least 8x8 */
1009
+ if (var->xres < 8 || var->yres < 8)
1010
+ return -EINVAL;
1011
+
1012
+ /* Too huge resolution causes multiplication overflow. */
1013
+ if (check_mul_overflow(var->xres, var->yres, &unused) ||
1014
+ check_mul_overflow(var->xres_virtual, var->yres_virtual, &unused))
1015
+ return -EINVAL;
1016
+
1017
+ ret = info->fbops->fb_check_var(var, info);
1018
+
1019
+ if (ret)
1020
+ return ret;
1021
+
1022
+ /* verify that virtual resolution >= physical resolution */
1023
+ if (var->xres_virtual < var->xres ||
1024
+ var->yres_virtual < var->yres) {
1025
+ pr_warn("WARNING: fbcon: Driver '%s' missed to adjust virtual screen size (%ux%u vs. %ux%u)\n",
1026
+ info->fix.id,
1027
+ var->xres_virtual, var->yres_virtual,
1028
+ var->xres, var->yres);
1029
+ return -EINVAL;
1030
+ }
1031
+
1032
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
1033
+ return 0;
1034
+
1035
+ if (info->fbops->fb_get_caps) {
1036
+ ret = fb_check_caps(info, var, activate);
10061037
10071038 if (ret)
1008
- goto done;
1039
+ return ret;
1040
+ }
10091041
1010
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1011
- struct fb_var_screeninfo old_var;
1012
- struct fb_videomode mode;
1042
+ old_var = info->var;
1043
+ info->var = *var;
10131044
1014
- if (info->fbops->fb_get_caps) {
1015
- ret = fb_check_caps(info, var, activate);
1045
+ if (info->fbops->fb_set_par) {
1046
+ ret = info->fbops->fb_set_par(info);
10161047
1017
- if (ret)
1018
- goto done;
1019
- }
1020
-
1021
- old_var = info->var;
1022
- info->var = *var;
1023
-
1024
- if (info->fbops->fb_set_par) {
1025
- ret = info->fbops->fb_set_par(info);
1026
-
1027
- if (ret) {
1028
- info->var = old_var;
1029
- printk(KERN_WARNING "detected "
1030
- "fb_set_par error, "
1031
- "error code: %d\n", ret);
1032
- goto done;
1033
- }
1034
- }
1035
-
1036
- fb_pan_display(info, &info->var);
1037
- fb_set_cmap(&info->cmap, info);
1038
- fb_var_to_videomode(&mode, &info->var);
1039
-
1040
- if (info->modelist.prev && info->modelist.next &&
1041
- !list_empty(&info->modelist))
1042
- ret = fb_add_videomode(&mode, &info->modelist);
1043
-
1044
- if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
1045
- struct fb_event event;
1046
- int evnt = (activate & FB_ACTIVATE_ALL) ?
1047
- FB_EVENT_MODE_CHANGE_ALL :
1048
- FB_EVENT_MODE_CHANGE;
1049
-
1050
- info->flags &= ~FBINFO_MISC_USEREVENT;
1051
- event.info = info;
1052
- event.data = &mode;
1053
- fb_notifier_call_chain(evnt, &event);
1054
- }
1048
+ if (ret) {
1049
+ info->var = old_var;
1050
+ printk(KERN_WARNING "detected "
1051
+ "fb_set_par error, "
1052
+ "error code: %d\n", ret);
1053
+ return ret;
10551054 }
10561055 }
10571056
1058
- done:
1059
- return ret;
1057
+ fb_pan_display(info, &info->var);
1058
+ fb_set_cmap(&info->cmap, info);
1059
+ fb_var_to_videomode(&mode, &info->var);
1060
+
1061
+ if (info->modelist.prev && info->modelist.next &&
1062
+ !list_empty(&info->modelist))
1063
+ ret = fb_add_videomode(&mode, &info->modelist);
1064
+
1065
+ if (ret)
1066
+ return ret;
1067
+
1068
+ event.info = info;
1069
+ event.data = &mode;
1070
+ fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event);
1071
+
1072
+ return 0;
10601073 }
10611074 EXPORT_SYMBOL(fb_set_var);
10621075
10631076 int
10641077 fb_blank(struct fb_info *info, int blank)
1065
-{
1078
+{
10661079 struct fb_event event;
1067
- int ret = -EINVAL, early_ret;
1080
+ int ret = -EINVAL;
10681081
1069
- if (blank > FB_BLANK_POWERDOWN)
1070
- blank = FB_BLANK_POWERDOWN;
1082
+ if (blank > FB_BLANK_POWERDOWN)
1083
+ blank = FB_BLANK_POWERDOWN;
10711084
10721085 event.info = info;
10731086 event.data = &blank;
10741087
1075
- early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
1076
-
10771088 if (info->fbops->fb_blank)
1078
- ret = info->fbops->fb_blank(blank, info);
1089
+ ret = info->fbops->fb_blank(blank, info);
10791090
10801091 if (!ret)
10811092 fb_notifier_call_chain(FB_EVENT_BLANK, &event);
1082
- else {
1083
- /*
1084
- * if fb_blank is failed then revert effects of
1085
- * the early blank event.
1086
- */
1087
- if (!early_ret)
1088
- fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event);
1089
- }
10901093
1091
- return ret;
1094
+ return ret;
10921095 }
10931096 EXPORT_SYMBOL(fb_blank);
1094
-
1095
-static int fb_get_dmabuf(struct fb_info *info, int flags)
1096
-{
1097
-#ifdef CONFIG_DMA_SHARED_BUFFER
1098
- struct dma_buf *dmabuf;
1099
-
1100
- if (!info->fbops->fb_dmabuf_export)
1101
- return -ENOTTY;
1102
-
1103
- dmabuf = info->fbops->fb_dmabuf_export(info);
1104
- if (IS_ERR(dmabuf))
1105
- return PTR_ERR(dmabuf);
1106
-
1107
- return dma_buf_fd(dmabuf, flags);
1108
-#else
1109
- return -ENOTTY;
1110
-#endif
1111
-}
11121097
11131098 static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
11141099 unsigned long arg)
11151100 {
1116
- struct fb_ops *fb;
1101
+ const struct fb_ops *fb;
11171102 struct fb_var_screeninfo var;
11181103 struct fb_fix_screeninfo fix;
1119
- struct fb_con2fbmap con2fb;
11201104 struct fb_cmap cmap_from;
11211105 struct fb_cmap_user cmap;
1122
- struct fb_event event;
1123
- struct fb_dmabuf_export dmaexp;
11241106 void __user *argp = (void __user *)arg;
11251107 long ret = 0;
11261108
11271109 switch (cmd) {
11281110 case FBIOGET_VSCREENINFO:
1129
- if (!lock_fb_info(info))
1130
- return -ENODEV;
1111
+ lock_fb_info(info);
11311112 var = info->var;
11321113 unlock_fb_info(info);
11331114
....@@ -1137,22 +1118,22 @@
11371118 if (copy_from_user(&var, argp, sizeof(var)))
11381119 return -EFAULT;
11391120 console_lock();
1140
- if (!lock_fb_info(info)) {
1141
- console_unlock();
1142
- return -ENODEV;
1143
- }
1144
- info->flags |= FBINFO_MISC_USEREVENT;
1145
- ret = fb_set_var(info, &var);
1146
- info->flags &= ~FBINFO_MISC_USEREVENT;
1121
+ lock_fb_info(info);
1122
+ ret = fbcon_modechange_possible(info, &var);
1123
+ if (!ret)
1124
+ ret = fb_set_var(info, &var);
1125
+ if (!ret)
1126
+ fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
11471127 unlock_fb_info(info);
11481128 console_unlock();
11491129 if (!ret && copy_to_user(argp, &var, sizeof(var)))
11501130 ret = -EFAULT;
11511131 break;
11521132 case FBIOGET_FSCREENINFO:
1153
- if (!lock_fb_info(info))
1154
- return -ENODEV;
1133
+ lock_fb_info(info);
11551134 memcpy(&fix, &info->fix, sizeof(fix));
1135
+ if (info->flags & FBINFO_HIDE_SMEM_START)
1136
+ fix.smem_start = 0;
11561137 unlock_fb_info(info);
11571138
11581139 ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
....@@ -1165,8 +1146,7 @@
11651146 case FBIOGETCMAP:
11661147 if (copy_from_user(&cmap, argp, sizeof(cmap)))
11671148 return -EFAULT;
1168
- if (!lock_fb_info(info))
1169
- return -ENODEV;
1149
+ lock_fb_info(info);
11701150 cmap_from = info->cmap;
11711151 unlock_fb_info(info);
11721152 ret = fb_cmap_to_user(&cmap_from, &cmap);
....@@ -1175,10 +1155,7 @@
11751155 if (copy_from_user(&var, argp, sizeof(var)))
11761156 return -EFAULT;
11771157 console_lock();
1178
- if (!lock_fb_info(info)) {
1179
- console_unlock();
1180
- return -ENODEV;
1181
- }
1158
+ lock_fb_info(info);
11821159 ret = fb_pan_display(info, &var);
11831160 unlock_fb_info(info);
11841161 console_unlock();
....@@ -1189,73 +1166,22 @@
11891166 ret = -EINVAL;
11901167 break;
11911168 case FBIOGET_CON2FBMAP:
1192
- if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
1193
- return -EFAULT;
1194
- if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
1195
- return -EINVAL;
1196
- con2fb.framebuffer = -1;
1197
- event.data = &con2fb;
1198
- if (!lock_fb_info(info))
1199
- return -ENODEV;
1200
- event.info = info;
1201
- fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
1202
- unlock_fb_info(info);
1203
- ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
1169
+ ret = fbcon_get_con2fb_map_ioctl(argp);
12041170 break;
12051171 case FBIOPUT_CON2FBMAP:
1206
- if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
1207
- return -EFAULT;
1208
- if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
1209
- return -EINVAL;
1210
- if (con2fb.framebuffer >= FB_MAX)
1211
- return -EINVAL;
1212
- if (!registered_fb[con2fb.framebuffer])
1213
- request_module("fb%d", con2fb.framebuffer);
1214
- if (!registered_fb[con2fb.framebuffer]) {
1215
- ret = -EINVAL;
1216
- break;
1217
- }
1218
- event.data = &con2fb;
1219
- console_lock();
1220
- if (!lock_fb_info(info)) {
1221
- console_unlock();
1222
- return -ENODEV;
1223
- }
1224
- event.info = info;
1225
- ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
1226
- unlock_fb_info(info);
1227
- console_unlock();
1172
+ ret = fbcon_set_con2fb_map_ioctl(argp);
12281173 break;
12291174 case FBIOBLANK:
12301175 console_lock();
1231
- if (!lock_fb_info(info)) {
1232
- console_unlock();
1233
- return -ENODEV;
1234
- }
1235
- info->flags |= FBINFO_MISC_USEREVENT;
1176
+ lock_fb_info(info);
12361177 ret = fb_blank(info, arg);
1237
- info->flags &= ~FBINFO_MISC_USEREVENT;
1178
+ /* might again call into fb_blank */
1179
+ fbcon_fb_blanked(info, arg);
12381180 unlock_fb_info(info);
12391181 console_unlock();
12401182 break;
1241
- case FBIOGET_DMABUF:
1242
- if (copy_from_user(&dmaexp, argp, sizeof(dmaexp)))
1243
- return -EFAULT;
1244
-
1245
- if (!lock_fb_info(info))
1246
- return -ENODEV;
1247
- ret = fb_get_dmabuf(info, dmaexp.flags);
1248
- unlock_fb_info(info);
1249
-
1250
- if (ret < 0)
1251
- return ret;
1252
- dmaexp.fd = ret;
1253
-
1254
- ret = copy_to_user(argp, &dmaexp, sizeof(dmaexp)) ? -EFAULT : 0;
1255
- break;
12561183 default:
1257
- if (!lock_fb_info(info))
1258
- return -ENODEV;
1184
+ lock_fb_info(info);
12591185 fb = info->fbops;
12601186 if (fb->fb_ioctl)
12611187 ret = fb->fb_ioctl(info, cmd, arg);
....@@ -1375,9 +1301,10 @@
13751301 {
13761302 struct fb_fix_screeninfo fix;
13771303
1378
- if (!lock_fb_info(info))
1379
- return -ENODEV;
1304
+ lock_fb_info(info);
13801305 fix = info->fix;
1306
+ if (info->flags & FBINFO_HIDE_SMEM_START)
1307
+ fix.smem_start = 0;
13811308 unlock_fb_info(info);
13821309 return do_fscreeninfo_to_user(&fix, compat_ptr(arg));
13831310 }
....@@ -1386,7 +1313,7 @@
13861313 unsigned long arg)
13871314 {
13881315 struct fb_info *info = file_fb_info(file);
1389
- struct fb_ops *fb;
1316
+ const struct fb_ops *fb;
13901317 long ret = -ENOIOCTLCMD;
13911318
13921319 if (!info)
....@@ -1398,9 +1325,8 @@
13981325 case FBIOPAN_DISPLAY:
13991326 case FBIOGET_CON2FBMAP:
14001327 case FBIOPUT_CON2FBMAP:
1401
- case FBIOGET_DMABUF:
14021328 arg = (unsigned long) compat_ptr(arg);
1403
- /* fall through */
1329
+ fallthrough;
14041330 case FBIOBLANK:
14051331 ret = do_fb_ioctl(info, cmd, arg);
14061332 break;
....@@ -1427,18 +1353,23 @@
14271353 fb_mmap(struct file *file, struct vm_area_struct * vma)
14281354 {
14291355 struct fb_info *info = file_fb_info(file);
1430
- struct fb_ops *fb;
1356
+ int (*fb_mmap_fn)(struct fb_info *info, struct vm_area_struct *vma);
14311357 unsigned long mmio_pgoff;
14321358 unsigned long start;
14331359 u32 len;
14341360
14351361 if (!info)
14361362 return -ENODEV;
1437
- fb = info->fbops;
1438
- if (!fb)
1439
- return -ENODEV;
14401363 mutex_lock(&info->mm_lock);
1441
- if (fb->fb_mmap) {
1364
+
1365
+ fb_mmap_fn = info->fbops->fb_mmap;
1366
+
1367
+#if IS_ENABLED(CONFIG_FB_DEFERRED_IO)
1368
+ if (info->fbdefio)
1369
+ fb_mmap_fn = fb_deferred_io_mmap;
1370
+#endif
1371
+
1372
+ if (fb_mmap_fn) {
14421373 int res;
14431374
14441375 /*
....@@ -1446,7 +1377,7 @@
14461377 * SME protection is removed ahead of the call
14471378 */
14481379 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
1449
- res = fb->fb_mmap(info, vma);
1380
+ res = fb_mmap_fn(info, vma);
14501381 mutex_unlock(&info->mm_lock);
14511382 return res;
14521383 }
....@@ -1500,7 +1431,7 @@
15001431 if (IS_ERR(info))
15011432 return PTR_ERR(info);
15021433
1503
- mutex_lock(&info->lock);
1434
+ lock_fb_info(info);
15041435 if (!try_module_get(info->fbops->owner)) {
15051436 res = -ENODEV;
15061437 goto out;
....@@ -1516,24 +1447,24 @@
15161447 fb_deferred_io_open(info, inode, file);
15171448 #endif
15181449 out:
1519
- mutex_unlock(&info->lock);
1450
+ unlock_fb_info(info);
15201451 if (res)
15211452 put_fb_info(info);
15221453 return res;
15231454 }
15241455
1525
-static int
1456
+static int
15261457 fb_release(struct inode *inode, struct file *file)
15271458 __acquires(&info->lock)
15281459 __releases(&info->lock)
15291460 {
15301461 struct fb_info * const info = file->private_data;
15311462
1532
- mutex_lock(&info->lock);
1463
+ lock_fb_info(info);
15331464 if (info->fbops->fb_release)
15341465 info->fbops->fb_release(info,1);
15351466 module_put(info->fbops->owner);
1536
- mutex_unlock(&info->lock);
1467
+ unlock_fb_info(info);
15371468 put_fb_info(info);
15381469 return 0;
15391470 }
....@@ -1638,13 +1569,13 @@
16381569 return false;
16391570 }
16401571
1641
-static int do_unregister_framebuffer(struct fb_info *fb_info);
1572
+static void do_unregister_framebuffer(struct fb_info *fb_info);
16421573
16431574 #define VGA_FB_PHYS 0xA0000
1644
-static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
1645
- const char *name, bool primary)
1575
+static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
1576
+ const char *name, bool primary)
16461577 {
1647
- int i, ret;
1578
+ int i;
16481579
16491580 /* check all firmware fbs and kick off if the base addr overlaps */
16501581 for_each_registered_fb(i) {
....@@ -1658,15 +1589,11 @@
16581589 (primary && gen_aper && gen_aper->count &&
16591590 gen_aper->ranges[0].base == VGA_FB_PHYS)) {
16601591
1661
- printk(KERN_INFO "fb: switching to %s from %s\n",
1662
- name, registered_fb[i]->fix.id);
1663
- ret = do_unregister_framebuffer(registered_fb[i]);
1664
- if (ret)
1665
- return ret;
1592
+ printk(KERN_INFO "fb%d: switching to %s from %s\n",
1593
+ i, name, registered_fb[i]->fix.id);
1594
+ do_unregister_framebuffer(registered_fb[i]);
16661595 }
16671596 }
1668
-
1669
- return 0;
16701597 }
16711598
16721599 static bool lockless_register_fb;
....@@ -1677,17 +1604,14 @@
16771604 static int do_register_framebuffer(struct fb_info *fb_info)
16781605 {
16791606 int i, ret;
1680
- struct fb_event event;
16811607 struct fb_videomode mode;
16821608
16831609 if (fb_check_foreignness(fb_info))
16841610 return -ENOSYS;
16851611
1686
- ret = do_remove_conflicting_framebuffers(fb_info->apertures,
1687
- fb_info->fix.id,
1688
- fb_is_primary_device(fb_info));
1689
- if (ret)
1690
- return ret;
1612
+ do_remove_conflicting_framebuffers(fb_info->apertures,
1613
+ fb_info->fix.id,
1614
+ fb_is_primary_device(fb_info));
16911615
16921616 if (num_registered_fb == FB_MAX)
16931617 return -ENXIO;
....@@ -1719,7 +1643,7 @@
17191643 fb_info->pixmap.access_align = 32;
17201644 fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
17211645 }
1722
- }
1646
+ }
17231647 fb_info->pixmap.offset = 0;
17241648
17251649 if (!fb_info->pixmap.blit_x)
....@@ -1740,20 +1664,22 @@
17401664 fb_add_videomode(&mode, &fb_info->modelist);
17411665 registered_fb[i] = fb_info;
17421666
1743
- event.info = fb_info;
1667
+#ifdef CONFIG_GUMSTIX_AM200EPD
1668
+ {
1669
+ struct fb_event event;
1670
+ event.info = fb_info;
1671
+ fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
1672
+ }
1673
+#endif
1674
+
17441675 if (!lockless_register_fb)
17451676 console_lock();
17461677 else
17471678 atomic_inc(&ignore_console_lock_warning);
1748
- if (!lock_fb_info(fb_info)) {
1749
- ret = -ENODEV;
1750
- goto unlock_console;
1751
- }
1752
- ret = 0;
1753
-
1754
- fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
1679
+ lock_fb_info(fb_info);
1680
+ ret = fbcon_fb_registered(fb_info);
17551681 unlock_fb_info(fb_info);
1756
-unlock_console:
1682
+
17571683 if (!lockless_register_fb)
17581684 console_unlock();
17591685 else
....@@ -1761,44 +1687,43 @@
17611687 return ret;
17621688 }
17631689
1764
-static int unbind_console(struct fb_info *fb_info)
1690
+static void unbind_console(struct fb_info *fb_info)
17651691 {
1766
- struct fb_event event;
1767
- int ret;
17681692 int i = fb_info->node;
17691693
1770
- if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
1771
- return -EINVAL;
1694
+ if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
1695
+ return;
17721696
17731697 console_lock();
1774
- if (!lock_fb_info(fb_info)) {
1775
- console_unlock();
1776
- return -ENODEV;
1777
- }
1778
-
1779
- event.info = fb_info;
1780
- ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
1698
+ lock_fb_info(fb_info);
1699
+ fbcon_fb_unbind(fb_info);
17811700 unlock_fb_info(fb_info);
17821701 console_unlock();
1783
-
1784
- return ret;
17851702 }
17861703
1787
-static int __unlink_framebuffer(struct fb_info *fb_info);
1788
-
1789
-static int do_unregister_framebuffer(struct fb_info *fb_info)
1704
+static void unlink_framebuffer(struct fb_info *fb_info)
17901705 {
1791
- struct fb_event event;
1792
- int ret;
1706
+ int i;
17931707
1794
- ret = unbind_console(fb_info);
1708
+ i = fb_info->node;
1709
+ if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
1710
+ return;
17951711
1796
- if (ret)
1797
- return -EINVAL;
1712
+ if (!fb_info->dev)
1713
+ return;
1714
+
1715
+ device_destroy(fb_class, MKDEV(FB_MAJOR, i));
17981716
17991717 pm_vt_switch_unregister(fb_info->dev);
18001718
1801
- __unlink_framebuffer(fb_info);
1719
+ unbind_console(fb_info);
1720
+
1721
+ fb_info->dev = NULL;
1722
+}
1723
+
1724
+static void do_unregister_framebuffer(struct fb_info *fb_info)
1725
+{
1726
+ unlink_framebuffer(fb_info);
18021727 if (fb_info->pixmap.addr &&
18031728 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
18041729 kfree(fb_info->pixmap.addr);
....@@ -1806,58 +1731,104 @@
18061731 registered_fb[fb_info->node] = NULL;
18071732 num_registered_fb--;
18081733 fb_cleanup_device(fb_info);
1809
- event.info = fb_info;
1734
+#ifdef CONFIG_GUMSTIX_AM200EPD
1735
+ {
1736
+ struct fb_event event;
1737
+ event.info = fb_info;
1738
+ fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1739
+ }
1740
+#endif
18101741 console_lock();
1811
- fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1742
+ fbcon_fb_unregistered(fb_info);
18121743 console_unlock();
18131744
18141745 /* this may free fb info */
18151746 put_fb_info(fb_info);
1816
- return 0;
18171747 }
18181748
1819
-static int __unlink_framebuffer(struct fb_info *fb_info)
1820
-{
1821
- int i;
1822
-
1823
- i = fb_info->node;
1824
- if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
1825
- return -EINVAL;
1826
-
1827
- if (fb_info->dev) {
1828
- device_destroy(fb_class, MKDEV(FB_MAJOR, i));
1829
- fb_info->dev = NULL;
1830
- }
1831
-
1832
- return 0;
1833
-}
1834
-
1835
-int unlink_framebuffer(struct fb_info *fb_info)
1836
-{
1837
- int ret;
1838
-
1839
- ret = __unlink_framebuffer(fb_info);
1840
- if (ret)
1841
- return ret;
1842
-
1843
- unbind_console(fb_info);
1844
-
1845
- return 0;
1846
-}
1847
-EXPORT_SYMBOL(unlink_framebuffer);
1848
-
1749
+/**
1750
+ * remove_conflicting_framebuffers - remove firmware-configured framebuffers
1751
+ * @a: memory range, users of which are to be removed
1752
+ * @name: requesting driver name
1753
+ * @primary: also kick vga16fb if present
1754
+ *
1755
+ * This function removes framebuffer devices (initialized by firmware/bootloader)
1756
+ * which use memory range described by @a. If @a is NULL all such devices are
1757
+ * removed.
1758
+ */
18491759 int remove_conflicting_framebuffers(struct apertures_struct *a,
18501760 const char *name, bool primary)
18511761 {
1852
- int ret;
1762
+ bool do_free = false;
1763
+
1764
+ if (!a) {
1765
+ a = alloc_apertures(1);
1766
+ if (!a)
1767
+ return -ENOMEM;
1768
+
1769
+ a->ranges[0].base = 0;
1770
+ a->ranges[0].size = ~0;
1771
+ do_free = true;
1772
+ }
18531773
18541774 mutex_lock(&registration_lock);
1855
- ret = do_remove_conflicting_framebuffers(a, name, primary);
1775
+ do_remove_conflicting_framebuffers(a, name, primary);
18561776 mutex_unlock(&registration_lock);
18571777
1858
- return ret;
1778
+ if (do_free)
1779
+ kfree(a);
1780
+
1781
+ return 0;
18591782 }
18601783 EXPORT_SYMBOL(remove_conflicting_framebuffers);
1784
+
1785
+/**
1786
+ * remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
1787
+ * @pdev: PCI device
1788
+ * @name: requesting driver name
1789
+ *
1790
+ * This function removes framebuffer devices (eg. initialized by firmware)
1791
+ * using memory range configured for any of @pdev's memory bars.
1792
+ *
1793
+ * The function assumes that PCI device with shadowed ROM drives a primary
1794
+ * display and so kicks out vga16fb.
1795
+ */
1796
+int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name)
1797
+{
1798
+ struct apertures_struct *ap;
1799
+ bool primary = false;
1800
+ int err, idx, bar;
1801
+
1802
+ for (idx = 0, bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
1803
+ if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
1804
+ continue;
1805
+ idx++;
1806
+ }
1807
+
1808
+ ap = alloc_apertures(idx);
1809
+ if (!ap)
1810
+ return -ENOMEM;
1811
+
1812
+ for (idx = 0, bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
1813
+ if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
1814
+ continue;
1815
+ ap->ranges[idx].base = pci_resource_start(pdev, bar);
1816
+ ap->ranges[idx].size = pci_resource_len(pdev, bar);
1817
+ pci_dbg(pdev, "%s: bar %d: 0x%lx -> 0x%lx\n", __func__, bar,
1818
+ (unsigned long)pci_resource_start(pdev, bar),
1819
+ (unsigned long)pci_resource_end(pdev, bar));
1820
+ idx++;
1821
+ }
1822
+
1823
+#ifdef CONFIG_X86
1824
+ primary = pdev->resource[PCI_ROM_RESOURCE].flags &
1825
+ IORESOURCE_ROM_SHADOW;
1826
+#endif
1827
+ err = remove_conflicting_framebuffers(ap, name, primary);
1828
+ kfree(ap);
1829
+ return err;
1830
+}
1831
+EXPORT_SYMBOL(remove_conflicting_pci_framebuffers);
18611832
18621833 /**
18631834 * register_framebuffer - registers a frame buffer device
....@@ -1897,16 +1868,12 @@
18971868 * that the driver implements fb_open() and fb_release() to
18981869 * check that no processes are using the device.
18991870 */
1900
-int
1871
+void
19011872 unregister_framebuffer(struct fb_info *fb_info)
19021873 {
1903
- int ret;
1904
-
19051874 mutex_lock(&registration_lock);
1906
- ret = do_unregister_framebuffer(fb_info);
1875
+ do_unregister_framebuffer(fb_info);
19071876 mutex_unlock(&registration_lock);
1908
-
1909
- return ret;
19101877 }
19111878 EXPORT_SYMBOL(unregister_framebuffer);
19121879
....@@ -1921,15 +1888,14 @@
19211888 */
19221889 void fb_set_suspend(struct fb_info *info, int state)
19231890 {
1924
- struct fb_event event;
1891
+ WARN_CONSOLE_UNLOCKED();
19251892
1926
- event.info = info;
19271893 if (state) {
1928
- fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
1894
+ fbcon_suspended(info);
19291895 info->state = FBINFO_STATE_SUSPENDED;
19301896 } else {
19311897 info->state = FBINFO_STATE_RUNNING;
1932
- fb_notifier_call_chain(FB_EVENT_RESUME, &event);
1898
+ fbcon_resumed(info);
19331899 }
19341900 }
19351901 EXPORT_SYMBOL(fb_set_suspend);
....@@ -1997,12 +1963,11 @@
19971963
19981964 int fb_new_modelist(struct fb_info *info)
19991965 {
2000
- struct fb_event event;
20011966 struct fb_var_screeninfo var = info->var;
20021967 struct list_head *pos, *n;
20031968 struct fb_modelist *modelist;
20041969 struct fb_videomode *m, mode;
2005
- int err = 1;
1970
+ int err;
20061971
20071972 list_for_each_safe(pos, n, &info->modelist) {
20081973 modelist = list_entry(pos, struct fb_modelist, list);
....@@ -2017,14 +1982,12 @@
20171982 }
20181983 }
20191984
2020
- err = 1;
1985
+ if (list_empty(&info->modelist))
1986
+ return 1;
20211987
2022
- if (!list_empty(&info->modelist)) {
2023
- event.info = info;
2024
- err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
2025
- }
1988
+ fbcon_new_modelist(info);
20261989
2027
- return err;
1990
+ return 0;
20281991 }
20291992
20301993 MODULE_LICENSE("GPL");