| .. | .. |
|---|
| 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"); |
|---|