.. | .. |
---|
28 | 28 | #include <linux/seq_file.h> |
---|
29 | 29 | #include <linux/console.h> |
---|
30 | 30 | #include <linux/kmod.h> |
---|
31 | | -#include <linux/dma-buf.h> |
---|
32 | 31 | #include <linux/err.h> |
---|
33 | 32 | #include <linux/device.h> |
---|
34 | 33 | #include <linux/efi.h> |
---|
35 | 34 | #include <linux/fb.h> |
---|
36 | 35 | #include <linux/fbcon.h> |
---|
37 | 36 | #include <linux/mem_encrypt.h> |
---|
| 37 | +#include <linux/pci.h> |
---|
38 | 38 | |
---|
39 | 39 | #include <asm/fb.h> |
---|
40 | 40 | |
---|
.. | .. |
---|
52 | 52 | |
---|
53 | 53 | int num_registered_fb __read_mostly; |
---|
54 | 54 | EXPORT_SYMBOL(num_registered_fb); |
---|
| 55 | + |
---|
| 56 | +bool fb_center_logo __read_mostly; |
---|
| 57 | + |
---|
| 58 | +int fb_logo_count __read_mostly = -1; |
---|
55 | 59 | |
---|
56 | 60 | static struct fb_info *get_fb_info(unsigned int idx) |
---|
57 | 61 | { |
---|
.. | .. |
---|
76 | 80 | if (fb_info->fbops->fb_destroy) |
---|
77 | 81 | fb_info->fbops->fb_destroy(fb_info); |
---|
78 | 82 | } |
---|
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); |
---|
90 | 83 | |
---|
91 | 84 | /* |
---|
92 | 85 | * Helpers |
---|
.. | .. |
---|
509 | 502 | fb_set_logo(info, logo, logo_new, fb_logo.depth); |
---|
510 | 503 | } |
---|
511 | 504 | |
---|
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 | + |
---|
514 | 523 | image.width = logo->width; |
---|
515 | 524 | image.height = logo->height; |
---|
516 | 525 | |
---|
.. | .. |
---|
528 | 537 | info->pseudo_palette = saved_pseudo_palette; |
---|
529 | 538 | kfree(logo_new); |
---|
530 | 539 | kfree(logo_rotate); |
---|
531 | | - return logo->height; |
---|
| 540 | + return image.dy + logo->height; |
---|
532 | 541 | } |
---|
533 | 542 | |
---|
534 | 543 | |
---|
.. | .. |
---|
580 | 589 | unsigned int i; |
---|
581 | 590 | |
---|
582 | 591 | 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); |
---|
585 | 594 | |
---|
586 | 595 | return y; |
---|
587 | 596 | } |
---|
.. | .. |
---|
607 | 616 | { |
---|
608 | 617 | int depth = fb_get_color_depth(&info->var, &info->fix); |
---|
609 | 618 | unsigned int yres; |
---|
| 619 | + int height; |
---|
610 | 620 | |
---|
611 | 621 | memset(&fb_logo, 0, sizeof(struct logo_data)); |
---|
612 | 622 | |
---|
613 | 623 | if (info->flags & FBINFO_MISC_TILEBLITTING || |
---|
614 | | - info->fbops->owner) |
---|
| 624 | + info->fbops->owner || !fb_logo_count) |
---|
615 | 625 | return 0; |
---|
616 | 626 | |
---|
617 | 627 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { |
---|
.. | .. |
---|
653 | 663 | fb_logo.depth = 1; |
---|
654 | 664 | |
---|
655 | 665 | |
---|
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 | + } |
---|
670 | 680 | |
---|
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); |
---|
672 | 686 | } |
---|
673 | 687 | |
---|
674 | 688 | int fb_show_logo(struct fb_info *info, int rotate) |
---|
675 | 689 | { |
---|
| 690 | + unsigned int count; |
---|
676 | 691 | int y; |
---|
677 | 692 | |
---|
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); |
---|
680 | 698 | y = fb_show_extra_logos(info, y, rotate); |
---|
681 | 699 | |
---|
682 | 700 | return y; |
---|
.. | .. |
---|
759 | 777 | |
---|
760 | 778 | if (info->fbops->fb_read) |
---|
761 | 779 | return info->fbops->fb_read(info, buf, count, ppos); |
---|
762 | | - |
---|
| 780 | + |
---|
763 | 781 | total_size = info->screen_size; |
---|
764 | 782 | |
---|
765 | 783 | if (total_size == 0) |
---|
.. | .. |
---|
824 | 842 | |
---|
825 | 843 | if (info->fbops->fb_write) |
---|
826 | 844 | return info->fbops->fb_write(info, buf, count, ppos); |
---|
827 | | - |
---|
| 845 | + |
---|
828 | 846 | total_size = info->screen_size; |
---|
829 | 847 | |
---|
830 | 848 | if (total_size == 0) |
---|
.. | .. |
---|
919 | 937 | static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, |
---|
920 | 938 | u32 activate) |
---|
921 | 939 | { |
---|
922 | | - struct fb_event event; |
---|
923 | 940 | struct fb_blit_caps caps, fbcaps; |
---|
924 | 941 | int err = 0; |
---|
925 | 942 | |
---|
926 | 943 | memset(&caps, 0, sizeof(caps)); |
---|
927 | 944 | memset(&fbcaps, 0, sizeof(fbcaps)); |
---|
928 | 945 | caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; |
---|
929 | | - event.info = info; |
---|
930 | | - event.data = ∩︀ |
---|
931 | | - fb_notifier_call_chain(FB_EVENT_GET_REQ, &event); |
---|
| 946 | + fbcon_get_requirement(info, &caps); |
---|
932 | 947 | info->fbops->fb_get_caps(info, &fbcaps, var); |
---|
933 | 948 | |
---|
934 | 949 | if (((fbcaps.x ^ caps.x) & caps.x) || |
---|
.. | .. |
---|
942 | 957 | int |
---|
943 | 958 | fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) |
---|
944 | 959 | { |
---|
945 | | - int flags = info->flags; |
---|
946 | 960 | 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; |
---|
947 | 966 | |
---|
948 | 967 | if (var->activate & FB_ACTIVATE_INV_MODE) { |
---|
949 | 968 | struct fb_videomode mode1, mode2; |
---|
.. | .. |
---|
952 | 971 | fb_var_to_videomode(&mode2, &info->var); |
---|
953 | 972 | /* make sure we don't delete the videomode of current var */ |
---|
954 | 973 | ret = fb_mode_is_equal(&mode1, &mode2); |
---|
955 | | - |
---|
956 | 974 | 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); |
---|
962 | 978 | } |
---|
963 | 979 | |
---|
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; |
---|
970 | 981 | } |
---|
971 | 982 | |
---|
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; |
---|
976 | 986 | |
---|
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; |
---|
990 | 988 | |
---|
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) |
---|
998 | 1000 | return -EINVAL; |
---|
| 1001 | + } |
---|
999 | 1002 | |
---|
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 | + } |
---|
1004 | 1007 | |
---|
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); |
---|
1006 | 1037 | |
---|
1007 | 1038 | if (ret) |
---|
1008 | | - goto done; |
---|
| 1039 | + return ret; |
---|
| 1040 | + } |
---|
1009 | 1041 | |
---|
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; |
---|
1013 | 1044 | |
---|
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); |
---|
1016 | 1047 | |
---|
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; |
---|
1055 | 1054 | } |
---|
1056 | 1055 | } |
---|
1057 | 1056 | |
---|
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; |
---|
1060 | 1073 | } |
---|
1061 | 1074 | EXPORT_SYMBOL(fb_set_var); |
---|
1062 | 1075 | |
---|
1063 | 1076 | int |
---|
1064 | 1077 | fb_blank(struct fb_info *info, int blank) |
---|
1065 | | -{ |
---|
| 1078 | +{ |
---|
1066 | 1079 | struct fb_event event; |
---|
1067 | | - int ret = -EINVAL, early_ret; |
---|
| 1080 | + int ret = -EINVAL; |
---|
1068 | 1081 | |
---|
1069 | | - if (blank > FB_BLANK_POWERDOWN) |
---|
1070 | | - blank = FB_BLANK_POWERDOWN; |
---|
| 1082 | + if (blank > FB_BLANK_POWERDOWN) |
---|
| 1083 | + blank = FB_BLANK_POWERDOWN; |
---|
1071 | 1084 | |
---|
1072 | 1085 | event.info = info; |
---|
1073 | 1086 | event.data = ␣ |
---|
1074 | 1087 | |
---|
1075 | | - early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event); |
---|
1076 | | - |
---|
1077 | 1088 | if (info->fbops->fb_blank) |
---|
1078 | | - ret = info->fbops->fb_blank(blank, info); |
---|
| 1089 | + ret = info->fbops->fb_blank(blank, info); |
---|
1079 | 1090 | |
---|
1080 | 1091 | if (!ret) |
---|
1081 | 1092 | 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 | | - } |
---|
1090 | 1093 | |
---|
1091 | | - return ret; |
---|
| 1094 | + return ret; |
---|
1092 | 1095 | } |
---|
1093 | 1096 | 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 | | -} |
---|
1112 | 1097 | |
---|
1113 | 1098 | static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, |
---|
1114 | 1099 | unsigned long arg) |
---|
1115 | 1100 | { |
---|
1116 | | - struct fb_ops *fb; |
---|
| 1101 | + const struct fb_ops *fb; |
---|
1117 | 1102 | struct fb_var_screeninfo var; |
---|
1118 | 1103 | struct fb_fix_screeninfo fix; |
---|
1119 | | - struct fb_con2fbmap con2fb; |
---|
1120 | 1104 | struct fb_cmap cmap_from; |
---|
1121 | 1105 | struct fb_cmap_user cmap; |
---|
1122 | | - struct fb_event event; |
---|
1123 | | - struct fb_dmabuf_export dmaexp; |
---|
1124 | 1106 | void __user *argp = (void __user *)arg; |
---|
1125 | 1107 | long ret = 0; |
---|
1126 | 1108 | |
---|
1127 | 1109 | switch (cmd) { |
---|
1128 | 1110 | case FBIOGET_VSCREENINFO: |
---|
1129 | | - if (!lock_fb_info(info)) |
---|
1130 | | - return -ENODEV; |
---|
| 1111 | + lock_fb_info(info); |
---|
1131 | 1112 | var = info->var; |
---|
1132 | 1113 | unlock_fb_info(info); |
---|
1133 | 1114 | |
---|
.. | .. |
---|
1137 | 1118 | if (copy_from_user(&var, argp, sizeof(var))) |
---|
1138 | 1119 | return -EFAULT; |
---|
1139 | 1120 | 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); |
---|
1147 | 1127 | unlock_fb_info(info); |
---|
1148 | 1128 | console_unlock(); |
---|
1149 | 1129 | if (!ret && copy_to_user(argp, &var, sizeof(var))) |
---|
1150 | 1130 | ret = -EFAULT; |
---|
1151 | 1131 | break; |
---|
1152 | 1132 | case FBIOGET_FSCREENINFO: |
---|
1153 | | - if (!lock_fb_info(info)) |
---|
1154 | | - return -ENODEV; |
---|
| 1133 | + lock_fb_info(info); |
---|
1155 | 1134 | memcpy(&fix, &info->fix, sizeof(fix)); |
---|
| 1135 | + if (info->flags & FBINFO_HIDE_SMEM_START) |
---|
| 1136 | + fix.smem_start = 0; |
---|
1156 | 1137 | unlock_fb_info(info); |
---|
1157 | 1138 | |
---|
1158 | 1139 | ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0; |
---|
.. | .. |
---|
1165 | 1146 | case FBIOGETCMAP: |
---|
1166 | 1147 | if (copy_from_user(&cmap, argp, sizeof(cmap))) |
---|
1167 | 1148 | return -EFAULT; |
---|
1168 | | - if (!lock_fb_info(info)) |
---|
1169 | | - return -ENODEV; |
---|
| 1149 | + lock_fb_info(info); |
---|
1170 | 1150 | cmap_from = info->cmap; |
---|
1171 | 1151 | unlock_fb_info(info); |
---|
1172 | 1152 | ret = fb_cmap_to_user(&cmap_from, &cmap); |
---|
.. | .. |
---|
1175 | 1155 | if (copy_from_user(&var, argp, sizeof(var))) |
---|
1176 | 1156 | return -EFAULT; |
---|
1177 | 1157 | console_lock(); |
---|
1178 | | - if (!lock_fb_info(info)) { |
---|
1179 | | - console_unlock(); |
---|
1180 | | - return -ENODEV; |
---|
1181 | | - } |
---|
| 1158 | + lock_fb_info(info); |
---|
1182 | 1159 | ret = fb_pan_display(info, &var); |
---|
1183 | 1160 | unlock_fb_info(info); |
---|
1184 | 1161 | console_unlock(); |
---|
.. | .. |
---|
1189 | 1166 | ret = -EINVAL; |
---|
1190 | 1167 | break; |
---|
1191 | 1168 | 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); |
---|
1204 | 1170 | break; |
---|
1205 | 1171 | 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); |
---|
1228 | 1173 | break; |
---|
1229 | 1174 | case FBIOBLANK: |
---|
1230 | 1175 | 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); |
---|
1236 | 1177 | ret = fb_blank(info, arg); |
---|
1237 | | - info->flags &= ~FBINFO_MISC_USEREVENT; |
---|
| 1178 | + /* might again call into fb_blank */ |
---|
| 1179 | + fbcon_fb_blanked(info, arg); |
---|
1238 | 1180 | unlock_fb_info(info); |
---|
1239 | 1181 | console_unlock(); |
---|
1240 | 1182 | 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; |
---|
1256 | 1183 | default: |
---|
1257 | | - if (!lock_fb_info(info)) |
---|
1258 | | - return -ENODEV; |
---|
| 1184 | + lock_fb_info(info); |
---|
1259 | 1185 | fb = info->fbops; |
---|
1260 | 1186 | if (fb->fb_ioctl) |
---|
1261 | 1187 | ret = fb->fb_ioctl(info, cmd, arg); |
---|
.. | .. |
---|
1375 | 1301 | { |
---|
1376 | 1302 | struct fb_fix_screeninfo fix; |
---|
1377 | 1303 | |
---|
1378 | | - if (!lock_fb_info(info)) |
---|
1379 | | - return -ENODEV; |
---|
| 1304 | + lock_fb_info(info); |
---|
1380 | 1305 | fix = info->fix; |
---|
| 1306 | + if (info->flags & FBINFO_HIDE_SMEM_START) |
---|
| 1307 | + fix.smem_start = 0; |
---|
1381 | 1308 | unlock_fb_info(info); |
---|
1382 | 1309 | return do_fscreeninfo_to_user(&fix, compat_ptr(arg)); |
---|
1383 | 1310 | } |
---|
.. | .. |
---|
1386 | 1313 | unsigned long arg) |
---|
1387 | 1314 | { |
---|
1388 | 1315 | struct fb_info *info = file_fb_info(file); |
---|
1389 | | - struct fb_ops *fb; |
---|
| 1316 | + const struct fb_ops *fb; |
---|
1390 | 1317 | long ret = -ENOIOCTLCMD; |
---|
1391 | 1318 | |
---|
1392 | 1319 | if (!info) |
---|
.. | .. |
---|
1398 | 1325 | case FBIOPAN_DISPLAY: |
---|
1399 | 1326 | case FBIOGET_CON2FBMAP: |
---|
1400 | 1327 | case FBIOPUT_CON2FBMAP: |
---|
1401 | | - case FBIOGET_DMABUF: |
---|
1402 | 1328 | arg = (unsigned long) compat_ptr(arg); |
---|
1403 | | - /* fall through */ |
---|
| 1329 | + fallthrough; |
---|
1404 | 1330 | case FBIOBLANK: |
---|
1405 | 1331 | ret = do_fb_ioctl(info, cmd, arg); |
---|
1406 | 1332 | break; |
---|
.. | .. |
---|
1427 | 1353 | fb_mmap(struct file *file, struct vm_area_struct * vma) |
---|
1428 | 1354 | { |
---|
1429 | 1355 | 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); |
---|
1431 | 1357 | unsigned long mmio_pgoff; |
---|
1432 | 1358 | unsigned long start; |
---|
1433 | 1359 | u32 len; |
---|
1434 | 1360 | |
---|
1435 | 1361 | if (!info) |
---|
1436 | 1362 | return -ENODEV; |
---|
1437 | | - fb = info->fbops; |
---|
1438 | | - if (!fb) |
---|
1439 | | - return -ENODEV; |
---|
1440 | 1363 | 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) { |
---|
1442 | 1373 | int res; |
---|
1443 | 1374 | |
---|
1444 | 1375 | /* |
---|
.. | .. |
---|
1446 | 1377 | * SME protection is removed ahead of the call |
---|
1447 | 1378 | */ |
---|
1448 | 1379 | vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); |
---|
1449 | | - res = fb->fb_mmap(info, vma); |
---|
| 1380 | + res = fb_mmap_fn(info, vma); |
---|
1450 | 1381 | mutex_unlock(&info->mm_lock); |
---|
1451 | 1382 | return res; |
---|
1452 | 1383 | } |
---|
.. | .. |
---|
1500 | 1431 | if (IS_ERR(info)) |
---|
1501 | 1432 | return PTR_ERR(info); |
---|
1502 | 1433 | |
---|
1503 | | - mutex_lock(&info->lock); |
---|
| 1434 | + lock_fb_info(info); |
---|
1504 | 1435 | if (!try_module_get(info->fbops->owner)) { |
---|
1505 | 1436 | res = -ENODEV; |
---|
1506 | 1437 | goto out; |
---|
.. | .. |
---|
1516 | 1447 | fb_deferred_io_open(info, inode, file); |
---|
1517 | 1448 | #endif |
---|
1518 | 1449 | out: |
---|
1519 | | - mutex_unlock(&info->lock); |
---|
| 1450 | + unlock_fb_info(info); |
---|
1520 | 1451 | if (res) |
---|
1521 | 1452 | put_fb_info(info); |
---|
1522 | 1453 | return res; |
---|
1523 | 1454 | } |
---|
1524 | 1455 | |
---|
1525 | | -static int |
---|
| 1456 | +static int |
---|
1526 | 1457 | fb_release(struct inode *inode, struct file *file) |
---|
1527 | 1458 | __acquires(&info->lock) |
---|
1528 | 1459 | __releases(&info->lock) |
---|
1529 | 1460 | { |
---|
1530 | 1461 | struct fb_info * const info = file->private_data; |
---|
1531 | 1462 | |
---|
1532 | | - mutex_lock(&info->lock); |
---|
| 1463 | + lock_fb_info(info); |
---|
1533 | 1464 | if (info->fbops->fb_release) |
---|
1534 | 1465 | info->fbops->fb_release(info,1); |
---|
1535 | 1466 | module_put(info->fbops->owner); |
---|
1536 | | - mutex_unlock(&info->lock); |
---|
| 1467 | + unlock_fb_info(info); |
---|
1537 | 1468 | put_fb_info(info); |
---|
1538 | 1469 | return 0; |
---|
1539 | 1470 | } |
---|
.. | .. |
---|
1638 | 1569 | return false; |
---|
1639 | 1570 | } |
---|
1640 | 1571 | |
---|
1641 | | -static int do_unregister_framebuffer(struct fb_info *fb_info); |
---|
| 1572 | +static void do_unregister_framebuffer(struct fb_info *fb_info); |
---|
1642 | 1573 | |
---|
1643 | 1574 | #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) |
---|
1646 | 1577 | { |
---|
1647 | | - int i, ret; |
---|
| 1578 | + int i; |
---|
1648 | 1579 | |
---|
1649 | 1580 | /* check all firmware fbs and kick off if the base addr overlaps */ |
---|
1650 | 1581 | for_each_registered_fb(i) { |
---|
.. | .. |
---|
1658 | 1589 | (primary && gen_aper && gen_aper->count && |
---|
1659 | 1590 | gen_aper->ranges[0].base == VGA_FB_PHYS)) { |
---|
1660 | 1591 | |
---|
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]); |
---|
1666 | 1595 | } |
---|
1667 | 1596 | } |
---|
1668 | | - |
---|
1669 | | - return 0; |
---|
1670 | 1597 | } |
---|
1671 | 1598 | |
---|
1672 | 1599 | static bool lockless_register_fb; |
---|
.. | .. |
---|
1677 | 1604 | static int do_register_framebuffer(struct fb_info *fb_info) |
---|
1678 | 1605 | { |
---|
1679 | 1606 | int i, ret; |
---|
1680 | | - struct fb_event event; |
---|
1681 | 1607 | struct fb_videomode mode; |
---|
1682 | 1608 | |
---|
1683 | 1609 | if (fb_check_foreignness(fb_info)) |
---|
1684 | 1610 | return -ENOSYS; |
---|
1685 | 1611 | |
---|
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)); |
---|
1691 | 1615 | |
---|
1692 | 1616 | if (num_registered_fb == FB_MAX) |
---|
1693 | 1617 | return -ENXIO; |
---|
.. | .. |
---|
1719 | 1643 | fb_info->pixmap.access_align = 32; |
---|
1720 | 1644 | fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; |
---|
1721 | 1645 | } |
---|
1722 | | - } |
---|
| 1646 | + } |
---|
1723 | 1647 | fb_info->pixmap.offset = 0; |
---|
1724 | 1648 | |
---|
1725 | 1649 | if (!fb_info->pixmap.blit_x) |
---|
.. | .. |
---|
1740 | 1664 | fb_add_videomode(&mode, &fb_info->modelist); |
---|
1741 | 1665 | registered_fb[i] = fb_info; |
---|
1742 | 1666 | |
---|
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 | + |
---|
1744 | 1675 | if (!lockless_register_fb) |
---|
1745 | 1676 | console_lock(); |
---|
1746 | 1677 | else |
---|
1747 | 1678 | 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); |
---|
1755 | 1681 | unlock_fb_info(fb_info); |
---|
1756 | | -unlock_console: |
---|
| 1682 | + |
---|
1757 | 1683 | if (!lockless_register_fb) |
---|
1758 | 1684 | console_unlock(); |
---|
1759 | 1685 | else |
---|
.. | .. |
---|
1761 | 1687 | return ret; |
---|
1762 | 1688 | } |
---|
1763 | 1689 | |
---|
1764 | | -static int unbind_console(struct fb_info *fb_info) |
---|
| 1690 | +static void unbind_console(struct fb_info *fb_info) |
---|
1765 | 1691 | { |
---|
1766 | | - struct fb_event event; |
---|
1767 | | - int ret; |
---|
1768 | 1692 | int i = fb_info->node; |
---|
1769 | 1693 | |
---|
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; |
---|
1772 | 1696 | |
---|
1773 | 1697 | 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); |
---|
1781 | 1700 | unlock_fb_info(fb_info); |
---|
1782 | 1701 | console_unlock(); |
---|
1783 | | - |
---|
1784 | | - return ret; |
---|
1785 | 1702 | } |
---|
1786 | 1703 | |
---|
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) |
---|
1790 | 1705 | { |
---|
1791 | | - struct fb_event event; |
---|
1792 | | - int ret; |
---|
| 1706 | + int i; |
---|
1793 | 1707 | |
---|
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; |
---|
1795 | 1711 | |
---|
1796 | | - if (ret) |
---|
1797 | | - return -EINVAL; |
---|
| 1712 | + if (!fb_info->dev) |
---|
| 1713 | + return; |
---|
| 1714 | + |
---|
| 1715 | + device_destroy(fb_class, MKDEV(FB_MAJOR, i)); |
---|
1798 | 1716 | |
---|
1799 | 1717 | pm_vt_switch_unregister(fb_info->dev); |
---|
1800 | 1718 | |
---|
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); |
---|
1802 | 1727 | if (fb_info->pixmap.addr && |
---|
1803 | 1728 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) |
---|
1804 | 1729 | kfree(fb_info->pixmap.addr); |
---|
.. | .. |
---|
1806 | 1731 | registered_fb[fb_info->node] = NULL; |
---|
1807 | 1732 | num_registered_fb--; |
---|
1808 | 1733 | 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 |
---|
1810 | 1741 | console_lock(); |
---|
1811 | | - fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); |
---|
| 1742 | + fbcon_fb_unregistered(fb_info); |
---|
1812 | 1743 | console_unlock(); |
---|
1813 | 1744 | |
---|
1814 | 1745 | /* this may free fb info */ |
---|
1815 | 1746 | put_fb_info(fb_info); |
---|
1816 | | - return 0; |
---|
1817 | 1747 | } |
---|
1818 | 1748 | |
---|
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 | + */ |
---|
1849 | 1759 | int remove_conflicting_framebuffers(struct apertures_struct *a, |
---|
1850 | 1760 | const char *name, bool primary) |
---|
1851 | 1761 | { |
---|
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 | + } |
---|
1853 | 1773 | |
---|
1854 | 1774 | mutex_lock(®istration_lock); |
---|
1855 | | - ret = do_remove_conflicting_framebuffers(a, name, primary); |
---|
| 1775 | + do_remove_conflicting_framebuffers(a, name, primary); |
---|
1856 | 1776 | mutex_unlock(®istration_lock); |
---|
1857 | 1777 | |
---|
1858 | | - return ret; |
---|
| 1778 | + if (do_free) |
---|
| 1779 | + kfree(a); |
---|
| 1780 | + |
---|
| 1781 | + return 0; |
---|
1859 | 1782 | } |
---|
1860 | 1783 | 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); |
---|
1861 | 1832 | |
---|
1862 | 1833 | /** |
---|
1863 | 1834 | * register_framebuffer - registers a frame buffer device |
---|
.. | .. |
---|
1897 | 1868 | * that the driver implements fb_open() and fb_release() to |
---|
1898 | 1869 | * check that no processes are using the device. |
---|
1899 | 1870 | */ |
---|
1900 | | -int |
---|
| 1871 | +void |
---|
1901 | 1872 | unregister_framebuffer(struct fb_info *fb_info) |
---|
1902 | 1873 | { |
---|
1903 | | - int ret; |
---|
1904 | | - |
---|
1905 | 1874 | mutex_lock(®istration_lock); |
---|
1906 | | - ret = do_unregister_framebuffer(fb_info); |
---|
| 1875 | + do_unregister_framebuffer(fb_info); |
---|
1907 | 1876 | mutex_unlock(®istration_lock); |
---|
1908 | | - |
---|
1909 | | - return ret; |
---|
1910 | 1877 | } |
---|
1911 | 1878 | EXPORT_SYMBOL(unregister_framebuffer); |
---|
1912 | 1879 | |
---|
.. | .. |
---|
1921 | 1888 | */ |
---|
1922 | 1889 | void fb_set_suspend(struct fb_info *info, int state) |
---|
1923 | 1890 | { |
---|
1924 | | - struct fb_event event; |
---|
| 1891 | + WARN_CONSOLE_UNLOCKED(); |
---|
1925 | 1892 | |
---|
1926 | | - event.info = info; |
---|
1927 | 1893 | if (state) { |
---|
1928 | | - fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); |
---|
| 1894 | + fbcon_suspended(info); |
---|
1929 | 1895 | info->state = FBINFO_STATE_SUSPENDED; |
---|
1930 | 1896 | } else { |
---|
1931 | 1897 | info->state = FBINFO_STATE_RUNNING; |
---|
1932 | | - fb_notifier_call_chain(FB_EVENT_RESUME, &event); |
---|
| 1898 | + fbcon_resumed(info); |
---|
1933 | 1899 | } |
---|
1934 | 1900 | } |
---|
1935 | 1901 | EXPORT_SYMBOL(fb_set_suspend); |
---|
.. | .. |
---|
1997 | 1963 | |
---|
1998 | 1964 | int fb_new_modelist(struct fb_info *info) |
---|
1999 | 1965 | { |
---|
2000 | | - struct fb_event event; |
---|
2001 | 1966 | struct fb_var_screeninfo var = info->var; |
---|
2002 | 1967 | struct list_head *pos, *n; |
---|
2003 | 1968 | struct fb_modelist *modelist; |
---|
2004 | 1969 | struct fb_videomode *m, mode; |
---|
2005 | | - int err = 1; |
---|
| 1970 | + int err; |
---|
2006 | 1971 | |
---|
2007 | 1972 | list_for_each_safe(pos, n, &info->modelist) { |
---|
2008 | 1973 | modelist = list_entry(pos, struct fb_modelist, list); |
---|
.. | .. |
---|
2017 | 1982 | } |
---|
2018 | 1983 | } |
---|
2019 | 1984 | |
---|
2020 | | - err = 1; |
---|
| 1985 | + if (list_empty(&info->modelist)) |
---|
| 1986 | + return 1; |
---|
2021 | 1987 | |
---|
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); |
---|
2026 | 1989 | |
---|
2027 | | - return err; |
---|
| 1990 | + return 0; |
---|
2028 | 1991 | } |
---|
2029 | 1992 | |
---|
2030 | 1993 | MODULE_LICENSE("GPL"); |
---|