aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2007-05-08 03:39:37 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:32 -0400
commit38a3dc51852d8350b156ea909c5aa8767d71b005 (patch)
tree933e9a4b7b0a0d871aaccd7d44e9224ea6c4a0b5
parente15de77e74d429f14641ebe7a29ccd8aa6656f3c (diff)
fbdev: fbcon: check if mode can handle new screen
Check if the mode can properly display the screen. This will be needed by drivers where the capability is not constant with each mode. The function fb_set_var() will query fbcon the requirement, then it will query the driver (via a new hook fb_get_caps()) its capability. If the driver's capability cannot handle fbcon's requirement, then fb_set_var() will fail. For example, if a particular driver supports 2 modes where: mode1 = can only display 8x16 bitmaps mode2 = can display any bitmap then if current mode = mode2 and current font = 12x22 fbset <mode1> /* mode1 cannot handle 12x22 */ fbset will fail Signed-off-by: Antonino Daplas <adaplas@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/video/console/fbcon.c42
-rw-r--r--drivers/video/fbmem.c33
-rw-r--r--include/linux/fb.h12
3 files changed, 87 insertions, 0 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 6fc3501581d6..34899bd7c9f3 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3043,6 +3043,43 @@ static void fbcon_new_modelist(struct fb_info *info)
3043 } 3043 }
3044} 3044}
3045 3045
3046static void fbcon_get_requirement(struct fb_info *info,
3047 struct fb_blit_caps *caps)
3048{
3049 struct vc_data *vc;
3050 struct display *p;
3051 int charcnt;
3052
3053 if (caps->flags) {
3054 int i;
3055
3056 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3057 vc = vc_cons[i].d;
3058 if (vc && vc->vc_mode == KD_TEXT) {
3059 p = &fb_display[i];
3060 caps->x |= 1 << (vc->vc_font.width - 1);
3061 caps->y |= 1 << (vc->vc_font.height - 1);
3062 charcnt = (p->userfont) ?
3063 FNTCHARCNT(p->fontdata) : 256;
3064 if (caps->len < charcnt)
3065 caps->len = charcnt;
3066 }
3067 }
3068 } else {
3069 vc = vc_cons[fg_console].d;
3070
3071 if (vc && vc->vc_mode == KD_TEXT) {
3072 p = &fb_display[fg_console];
3073 caps->x |= 1 << (vc->vc_font.width - 1);
3074 caps->y |= 1 << (vc->vc_font.height - 1);
3075 charcnt = (p->userfont) ?
3076 FNTCHARCNT(p->fontdata) : 256;
3077 if (caps->len < charcnt)
3078 caps->len = charcnt;
3079 }
3080 }
3081}
3082
3046static int fbcon_event_notify(struct notifier_block *self, 3083static int fbcon_event_notify(struct notifier_block *self,
3047 unsigned long action, void *data) 3084 unsigned long action, void *data)
3048{ 3085{
@@ -3050,6 +3087,7 @@ static int fbcon_event_notify(struct notifier_block *self,
3050 struct fb_info *info = event->info; 3087 struct fb_info *info = event->info;
3051 struct fb_videomode *mode; 3088 struct fb_videomode *mode;
3052 struct fb_con2fbmap *con2fb; 3089 struct fb_con2fbmap *con2fb;
3090 struct fb_blit_caps *caps;
3053 int ret = 0; 3091 int ret = 0;
3054 3092
3055 /* 3093 /*
@@ -3098,6 +3136,10 @@ static int fbcon_event_notify(struct notifier_block *self,
3098 case FB_EVENT_NEW_MODELIST: 3136 case FB_EVENT_NEW_MODELIST:
3099 fbcon_new_modelist(info); 3137 fbcon_new_modelist(info);
3100 break; 3138 break;
3139 case FB_EVENT_GET_REQ:
3140 caps = event->data;
3141 fbcon_get_requirement(info, caps);
3142 break;
3101 } 3143 }
3102 3144
3103done: 3145done:
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index cd1407921af5..354711c84aaa 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -773,6 +773,29 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
773 return 0; 773 return 0;
774} 774}
775 775
776static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
777 u32 activate)
778{
779 struct fb_event event;
780 struct fb_blit_caps caps, fbcaps;
781 int err = 0;
782
783 memset(&caps, 0, sizeof(caps));
784 memset(&fbcaps, 0, sizeof(fbcaps));
785 caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
786 event.info = info;
787 event.data = &caps;
788 fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
789 info->fbops->fb_get_caps(info, &fbcaps, var);
790
791 if (((fbcaps.x ^ caps.x) & caps.x) ||
792 ((fbcaps.y ^ caps.y) & caps.y) ||
793 (fbcaps.len < caps.len))
794 err = -EINVAL;
795
796 return err;
797}
798
776int 799int
777fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) 800fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
778{ 801{
@@ -817,7 +840,15 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
817 struct fb_videomode mode; 840 struct fb_videomode mode;
818 int err = 0; 841 int err = 0;
819 842
843 if (info->fbops->fb_get_caps) {
844 err = fb_check_caps(info, var, activate);
845
846 if (err)
847 goto done;
848 }
849
820 info->var = *var; 850 info->var = *var;
851
821 if (info->fbops->fb_set_par) 852 if (info->fbops->fb_set_par)
822 info->fbops->fb_set_par(info); 853 info->fbops->fb_set_par(info);
823 854
@@ -843,6 +874,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
843 } 874 }
844 } 875 }
845 } 876 }
877
878 done:
846 return 0; 879 return 0;
847} 880}
848 881
diff --git a/include/linux/fb.h b/include/linux/fb.h
index a2f382c01cd2..dff7a728948c 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -527,12 +527,20 @@ struct fb_cursor_user {
527#define FB_EVENT_MODE_CHANGE_ALL 0x0B 527#define FB_EVENT_MODE_CHANGE_ALL 0x0B
528/* A software display blank change occured */ 528/* A software display blank change occured */
529#define FB_EVENT_CONBLANK 0x0C 529#define FB_EVENT_CONBLANK 0x0C
530/* Get drawing requirements */
531#define FB_EVENT_GET_REQ 0x0D
530 532
531struct fb_event { 533struct fb_event {
532 struct fb_info *info; 534 struct fb_info *info;
533 void *data; 535 void *data;
534}; 536};
535 537
538struct fb_blit_caps {
539 u32 x;
540 u32 y;
541 u32 len;
542 u32 flags;
543};
536 544
537extern int fb_register_client(struct notifier_block *nb); 545extern int fb_register_client(struct notifier_block *nb);
538extern int fb_unregister_client(struct notifier_block *nb); 546extern int fb_unregister_client(struct notifier_block *nb);
@@ -652,6 +660,10 @@ struct fb_ops {
652 660
653 /* restore saved state */ 661 /* restore saved state */
654 void (*fb_restore_state)(struct fb_info *info); 662 void (*fb_restore_state)(struct fb_info *info);
663
664 /* get capability given var */
665 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
666 struct fb_var_screeninfo *var);
655}; 667};
656 668
657#ifdef CONFIG_FB_TILEBLITTING 669#ifdef CONFIG_FB_TILEBLITTING