X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fvideo%2Fconsole%2Ffbcon.c;h=022282494d3fecee136f47d831e2dd4e534fe62d;hb=2dd550b90b03d5f236a18ae491bf6e70798469a8;hp=b7e143efa81d598ddc6ed54847bea8ca32dd277a;hpb=acba9cd01974353294ecd0c750581a6707d1ebe1;p=linux-2.6 diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index b7e143efa8..022282494d 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -75,16 +75,16 @@ #include #include #include /* For counting font checksums */ +#include #include #include -#include #ifdef CONFIG_ATARI #include #endif #ifdef CONFIG_MAC #include #endif -#if defined(__mc68000__) || defined(CONFIG_APUS) +#if defined(__mc68000__) #include #include #endif @@ -125,6 +125,20 @@ static int first_fb_vc; static int last_fb_vc = MAX_NR_CONSOLES - 1; static int fbcon_is_default = 1; static int fbcon_has_exited; +static int primary_device = -1; + +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY +static int map_override; + +static inline void fbcon_map_override(void) +{ + map_override = 1; +} +#else +static inline void fbcon_map_override(void) +{ +} +#endif /* CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY */ /* font data */ static char fontname[40]; @@ -133,7 +147,7 @@ static char fontname[40]; static int info_idx = -1; /* console rotation */ -static int rotate; +static int initial_rotation; static int fbcon_has_sysfs; static const struct consw fb_con; @@ -189,16 +203,14 @@ static __inline__ void ypan_down(struct vc_data *vc, int count); static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break); static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, - struct vc_data *vc); -static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var, - int unit); + int unit); static void fbcon_redraw_move(struct vc_data *vc, struct display *p, int line, int count, int dy); static void fbcon_modechanged(struct fb_info *info); static void fbcon_set_all_vcs(struct fb_info *info); static void fbcon_start(void); static void fbcon_exit(void); -static struct class_device *fbcon_class_device; +static struct device *fbcon_device; #ifdef CONFIG_MAC /* @@ -322,10 +334,7 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info, switch (depth) { case 1: { - int col = ~(0xfff << (max(info->var.green.length, - max(info->var.red.length, - info->var.blue.length)))) & 0xff; - + int col = mono_col(info); /* 0 or 1 */ int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0; int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col; @@ -497,13 +506,17 @@ static int __init fb_console_setup(char *this_opt) if (!strncmp(options, "map:", 4)) { options += 4; - if (*options) + if (*options) { for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { if (!options[j]) j = 0; con2fb_map_boot[i] = (options[j++]-'0') % FB_MAX; } + + fbcon_map_override(); + } + return 1; } @@ -521,9 +534,9 @@ static int __init fb_console_setup(char *this_opt) if (!strncmp(options, "rotate:", 7)) { options += 7; if (*options) - rotate = simple_strtoul(options, &options, 0); - if (rotate > 3) - rotate = 0; + initial_rotation = simple_strtoul(options, &options, 0); + if (initial_rotation > 3) + initial_rotation = 0; } } return 1; @@ -738,7 +751,9 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info, if (!err) { info->fbcon_par = ops; - set_blitting_type(vc, info); + + if (vc) + set_blitting_type(vc, info); } if (err) { @@ -800,11 +815,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, ops->flags |= FBCON_FLAGS_INIT; ops->graphics = 0; - - if (vc) - fbcon_set_disp(info, &info->var, vc); - else - fbcon_preset_disp(info, &info->var, unit); + fbcon_set_disp(info, &info->var, unit); if (show_logo) { struct vc_data *fg_vc = vc_cons[fg_console].d; @@ -975,7 +986,7 @@ static const char *fbcon_startup(void) ops->graphics = 1; ops->cur_rotate = -1; info->fbcon_par = ops; - p->con_rotate = rotate; + p->con_rotate = initial_rotation; set_blitting_type(vc, info); if (info->fix.type != FB_TYPE_TEXT) { @@ -1109,6 +1120,9 @@ static void fbcon_init(struct vc_data *vc, int init) if (var_to_display(p, &info->var, info)) return; + if (!info->fbcon_par) + con2fb_acquire_newinfo(vc, info, vc->vc_num, -1); + /* If we are not the first console on this fb, copy the font from that console */ t = &fb_display[fg_console]; @@ -1159,7 +1173,7 @@ static void fbcon_init(struct vc_data *vc, int init) con_copy_unimap(vc, svc); ops = info->fbcon_par; - p->con_rotate = rotate; + p->con_rotate = initial_rotation; set_blitting_type(vc, info); cols = vc->vc_cols; @@ -1375,36 +1389,29 @@ static int scrollback_phys_max = 0; static int scrollback_max = 0; static int scrollback_current = 0; -/* - * If no vc is existent yet, just set struct display - */ -static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var, - int unit) -{ - struct display *p = &fb_display[unit]; - struct display *t = &fb_display[fg_console]; - - if (var_to_display(p, var, info)) - return; - - p->fontdata = t->fontdata; - p->userfont = t->userfont; - if (p->userfont) - REFCOUNT(p->fontdata)++; -} - static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, - struct vc_data *vc) + int unit) { - struct display *p = &fb_display[vc->vc_num], *t; - struct vc_data **default_mode = vc->vc_display_fg; - struct vc_data *svc = *default_mode; + struct display *p, *t; + struct vc_data **default_mode, *vc; + struct vc_data *svc; struct fbcon_ops *ops = info->fbcon_par; int rows, cols, charcnt = 256; + p = &fb_display[unit]; + if (var_to_display(p, var, info)) return; + + vc = vc_cons[unit].d; + + if (!vc) + return; + + default_mode = vc->vc_display_fg; + svc = *default_mode; t = &fb_display[svc->vc_num]; + if (!vc->vc_font.data) { vc->vc_font.data = (void *)(p->fontdata = t->fontdata); vc->vc_font.width = (*default_mode)->vc_font.width; @@ -2158,7 +2165,7 @@ static __inline__ void updatescrollmode(struct display *p, } static int fbcon_resize(struct vc_data *vc, unsigned int width, - unsigned int height) + unsigned int height, unsigned int user) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; @@ -2395,7 +2402,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) update_screen(vc); } - if (fbcon_is_inactive(vc, info) || + if (mode_switch || fbcon_is_inactive(vc, info) || ops->blank_state != FB_BLANK_UNBLANK) fbcon_del_cursor_timer(info); else @@ -2785,7 +2792,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) { struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[fg_console]; + struct display *disp = &fb_display[fg_console]; int offset, limit, scrollback_old; if (softback_top) { @@ -2823,7 +2830,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) logo_shown = FBCON_LOGO_CANSHOW; } fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); - fbcon_redraw_softback(vc, p, lines); + fbcon_redraw_softback(vc, disp, lines); fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); return 0; } @@ -2845,9 +2852,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) fbcon_cursor(vc, CM_ERASE); - offset = p->yscroll - scrollback_current; - limit = p->vrows; - switch (p->scrollmode) { + offset = disp->yscroll - scrollback_current; + limit = disp->vrows; + switch (disp->scrollmode) { case SCROLL_WRAP_MOVE: info->var.vmode |= FB_VMODE_YWRAP; break; @@ -3004,9 +3011,48 @@ static int fbcon_mode_deleted(struct fb_info *info, return found; } -static int fbcon_fb_unregistered(int idx) +#ifdef CONFIG_VT_HW_CONSOLE_BINDING +static int fbcon_unbind(void) { - int i; + int ret; + + ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + return ret; +} +#else +static inline int fbcon_unbind(void) +{ + return -EINVAL; +} +#endif /* CONFIG_VT_HW_CONSOLE_BINDING */ + +static int fbcon_fb_unbind(int idx) +{ + int i, new_idx = -1, ret = 0; + + for (i = first_fb_vc; i <= last_fb_vc; i++) { + if (con2fb_map[i] != idx && + con2fb_map[i] != -1) { + new_idx = i; + break; + } + } + + if (new_idx != -1) { + for (i = first_fb_vc; i <= last_fb_vc; i++) { + if (con2fb_map[i] == idx) + set_con2fb_map(i, new_idx, 0); + } + } else + ret = fbcon_unbind(); + + return ret; +} + +static int fbcon_fb_unregistered(struct fb_info *info) +{ + int i, idx = info->node; for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map[i] == idx) @@ -3034,12 +3080,48 @@ static int fbcon_fb_unregistered(int idx) if (!num_registered_fb) unregister_con_driver(&fb_con); + + if (primary_device == idx) + primary_device = -1; + return 0; } -static int fbcon_fb_registered(int idx) +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY +static void fbcon_select_primary(struct fb_info *info) { - int ret = 0, i; + if (!map_override && primary_device == -1 && + fb_is_primary_device(info)) { + int i; + + printk(KERN_INFO "fbcon: %s (fb%i) is primary device\n", + info->fix.id, info->node); + primary_device = info->node; + + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map_boot[i] = primary_device; + + if (con_is_bound(&fb_con)) { + printk(KERN_INFO "fbcon: Remapping primary device, " + "fb%i, to tty %i-%i\n", info->node, + first_fb_vc + 1, last_fb_vc + 1); + info_idx = primary_device; + } + } + +} +#else +static inline void fbcon_select_primary(struct fb_info *info) +{ + return; +} +#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ + +static int fbcon_fb_registered(struct fb_info *info) +{ + int ret = 0, i, idx = info->node; + + fbcon_select_primary(info); if (info_idx == -1) { for (i = first_fb_vc; i <= last_fb_vc; i++) { @@ -3053,8 +3135,7 @@ static int fbcon_fb_registered(int idx) ret = fbcon_takeover(1); } else { for (i = first_fb_vc; i <= last_fb_vc; i++) { - if (con2fb_map_boot[i] == idx && - con2fb_map[i] == -1) + if (con2fb_map_boot[i] == idx) set_con2fb_map(i, idx, 0); } } @@ -3101,12 +3182,7 @@ static void fbcon_new_modelist(struct fb_info *info) mode = fb_find_nearest_mode(fb_display[i].mode, &info->modelist); fb_videomode_to_var(&var, mode); - - if (vc) - fbcon_set_disp(info, &var, vc); - else - fbcon_preset_disp(info, &var, i); - + fbcon_set_disp(info, &var, vc->vc_num); } } @@ -3181,11 +3257,14 @@ static int fbcon_event_notify(struct notifier_block *self, mode = event->data; ret = fbcon_mode_deleted(info, mode); break; + case FB_EVENT_FB_UNBIND: + ret = fbcon_fb_unbind(info->node); + break; case FB_EVENT_FB_REGISTERED: - ret = fbcon_fb_registered(info->node); + ret = fbcon_fb_registered(info); break; case FB_EVENT_FB_UNREGISTERED: - ret = fbcon_fb_unregistered(info->node); + ret = fbcon_fb_unregistered(info); break; case FB_EVENT_SET_CONSOLE_MAP: con2fb = event->data; @@ -3246,8 +3325,9 @@ static struct notifier_block fbcon_event_notifier = { .notifier_call = fbcon_event_notify, }; -static ssize_t store_rotate(struct class_device *class_device, - const char *buf, size_t count) +static ssize_t store_rotate(struct device *device, + struct device_attribute *attr, const char *buf, + size_t count) { struct fb_info *info; int rotate, idx; @@ -3270,8 +3350,9 @@ err: return count; } -static ssize_t store_rotate_all(struct class_device *class_device, - const char *buf, size_t count) +static ssize_t store_rotate_all(struct device *device, + struct device_attribute *attr,const char *buf, + size_t count) { struct fb_info *info; int rotate, idx; @@ -3294,7 +3375,8 @@ err: return count; } -static ssize_t show_rotate(struct class_device *class_device, char *buf) +static ssize_t show_rotate(struct device *device, + struct device_attribute *attr,char *buf) { struct fb_info *info; int rotate = 0, idx; @@ -3315,7 +3397,8 @@ err: return snprintf(buf, PAGE_SIZE, "%d\n", rotate); } -static ssize_t show_cursor_blink(struct class_device *class_device, char *buf) +static ssize_t show_cursor_blink(struct device *device, + struct device_attribute *attr, char *buf) { struct fb_info *info; struct fbcon_ops *ops; @@ -3342,7 +3425,8 @@ err: return snprintf(buf, PAGE_SIZE, "%d\n", blink); } -static ssize_t store_cursor_blink(struct class_device *clas_device, +static ssize_t store_cursor_blink(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) { struct fb_info *info; @@ -3378,22 +3462,21 @@ err: return count; } -static struct class_device_attribute class_device_attrs[] = { +static struct device_attribute device_attrs[] = { __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), __ATTR(cursor_blink, S_IRUGO|S_IWUSR, show_cursor_blink, store_cursor_blink), }; -static int fbcon_init_class_device(void) +static int fbcon_init_device(void) { int i, error = 0; fbcon_has_sysfs = 1; - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { - error = class_device_create_file(fbcon_class_device, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { + error = device_create_file(fbcon_device, &device_attrs[i]); if (error) break; @@ -3401,8 +3484,7 @@ static int fbcon_init_class_device(void) if (error) { while (--i >= 0) - class_device_remove_file(fbcon_class_device, - &class_device_attrs[i]); + device_remove_file(fbcon_device, &device_attrs[i]); fbcon_has_sysfs = 0; } @@ -3488,16 +3570,15 @@ static int __init fb_console_init(void) acquire_console_sem(); fb_register_client(&fbcon_event_notifier); - fbcon_class_device = - class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon"); + fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), "fbcon"); - if (IS_ERR(fbcon_class_device)) { - printk(KERN_WARNING "Unable to create class_device " + if (IS_ERR(fbcon_device)) { + printk(KERN_WARNING "Unable to create device " "for fbcon; errno = %ld\n", - PTR_ERR(fbcon_class_device)); - fbcon_class_device = NULL; + PTR_ERR(fbcon_device)); + fbcon_device = NULL; } else - fbcon_init_class_device(); + fbcon_init_device(); for (i = 0; i < MAX_NR_CONSOLES; i++) con2fb_map[i] = -1; @@ -3511,14 +3592,13 @@ module_init(fb_console_init); #ifdef MODULE -static void __exit fbcon_deinit_class_device(void) +static void __exit fbcon_deinit_device(void) { int i; if (fbcon_has_sysfs) { - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_remove_file(fbcon_class_device, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) + device_remove_file(fbcon_device, &device_attrs[i]); fbcon_has_sysfs = 0; } @@ -3528,8 +3608,8 @@ static void __exit fb_console_exit(void) { acquire_console_sem(); fb_unregister_client(&fbcon_event_notifier); - fbcon_deinit_class_device(); - class_device_destroy(fb_class, MKDEV(0, 0)); + fbcon_deinit_device(); + device_destroy(fb_class, MKDEV(0, 0)); fbcon_exit(); release_console_sem(); unregister_con_driver(&fb_con);