--- zzzz-none-000/linux-3.10.107/drivers/video/console/fbcon.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/video/console/fbcon.c 2021-02-04 17:41:59.000000000 +0000 @@ -146,9 +146,6 @@ static int fbcon_set_origin(struct vc_data *); -#define CURSOR_DRAW_DELAY (1) - -static int vbl_cursor_cnt; static int fbcon_cursor_noblink; #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) @@ -404,8 +401,8 @@ struct fb_info *info = (struct fb_info *) dev_addr; struct fbcon_ops *ops = info->fbcon_par; - schedule_work(&info->queue); - mod_timer(&ops->cursor_timer, jiffies + HZ/5); + queue_work(system_power_efficient_wq, &info->queue); + mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies); } static void fbcon_add_cursor_timer(struct fb_info *info) @@ -420,7 +417,7 @@ init_timer(&ops->cursor_timer); ops->cursor_timer.function = cursor_timer_handler; - ops->cursor_timer.expires = jiffies + HZ / 5; + ops->cursor_timer.expires = jiffies + ops->cur_blink_jiffies; ops->cursor_timer.data = (unsigned long ) info; add_timer(&ops->cursor_timer); ops->flags |= FBCON_FLAGS_CURSOR_TIMER; @@ -448,8 +445,10 @@ return 1; while ((options = strsep(&this_opt, ",")) != NULL) { - if (!strncmp(options, "font:", 5)) + if (!strncmp(options, "font:", 5)) { strlcpy(fontname, options + 5, sizeof(fontname)); + continue; + } if (!strncmp(options, "scrollback:", 11)) { options += 11; @@ -457,13 +456,9 @@ fbcon_softback_size = simple_strtoul(options, &options, 0); if (*options == 'k' || *options == 'K') { fbcon_softback_size *= 1024; - options++; } - if (*options != ',') - return 1; - options++; - } else - return 1; + } + continue; } if (!strncmp(options, "map:", 4)) { @@ -478,8 +473,7 @@ fbcon_map_override(); } - - return 1; + continue; } if (!strncmp(options, "vc:", 3)) { @@ -491,7 +485,8 @@ if (*options++ == '-') last_fb_vc = simple_strtoul(options, &options, 10) - 1; fbcon_is_default = 0; - } + continue; + } if (!strncmp(options, "rotate:", 7)) { options += 7; @@ -499,6 +494,7 @@ initial_rotation = simple_strtoul(options, &options, 0); if (initial_rotation > 3) initial_rotation = 0; + continue; } } return 1; @@ -556,34 +552,6 @@ return err; } -static int fbcon_takeover(int show_logo) -{ - int err, i; - - if (!num_registered_fb) - return -ENODEV; - - if (!show_logo) - logo_shown = FBCON_LOGO_DONTSHOW; - - for (i = first_fb_vc; i <= last_fb_vc; i++) - con2fb_map[i] = info_idx; - - err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, - fbcon_is_default); - - if (err) { - for (i = first_fb_vc; i <= last_fb_vc; i++) { - con2fb_map[i] = -1; - } - info_idx = -1; - } else { - fbcon_has_console_bind = 1; - } - - return err; -} - #ifdef MODULE static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, int cols, int rows, int new_cols, int new_rows) @@ -741,6 +709,7 @@ } if (!err) { + ops->cur_blink_jiffies = HZ / 5; info->fbcon_par = ops; if (vc) @@ -776,6 +745,7 @@ fbcon_del_cursor_timer(oldinfo); kfree(ops->cursor_state.mask); kfree(ops->cursor_data); + kfree(ops->cursor_src); kfree(ops->fontbuffer); kfree(oldinfo->fbcon_par); oldinfo->fbcon_par = NULL; @@ -787,7 +757,7 @@ newinfo in an undefined state. Thus, a call to fb_set_par() may be needed for the newinfo. */ - if (newinfo->fbops->fb_set_par) { + if (newinfo && newinfo->fbops->fb_set_par) { ret = newinfo->fbops->fb_set_par(newinfo); if (ret) @@ -901,7 +871,7 @@ /* * Low Level Operations */ -/* NOTE: fbcon cannot be __init: it may be called from take_over_console later */ +/* NOTE: fbcon cannot be __init: it may be called from do_take_over_console later */ static int var_to_display(struct display *disp, struct fb_var_screeninfo *var, struct fb_info *info) @@ -987,6 +957,7 @@ ops->currcon = -1; ops->graphics = 1; ops->cur_rotate = -1; + ops->cur_blink_jiffies = HZ / 5; info->fbcon_par = ops; p->con_rotate = initial_rotation; set_blitting_type(vc, info); @@ -1124,6 +1095,7 @@ con_copy_unimap(vc, svc); ops = info->fbcon_par; + ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); p->con_rotate = initial_rotation; set_blitting_type(vc, info); @@ -1342,6 +1314,8 @@ int y; int c = scr_readw((u16 *) vc->vc_pos); + ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) return; @@ -1362,7 +1336,6 @@ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1), get_color(vc, info, c, 0)); - vbl_cursor_cnt = CURSOR_DRAW_DELAY; } static int scrollback_phys_max = 0; @@ -3069,8 +3042,31 @@ if (con2fb_map[i] == idx) set_con2fb_map(i, new_idx, 0); } - } else + } else { + struct fb_info *info = registered_fb[idx]; + + /* This is sort of like set_con2fb_map, except it maps + * the consoles to no device and then releases the + * oldinfo to free memory and cancel the cursor blink + * timer. I can imagine this just becoming part of + * set_con2fb_map where new_idx is -1 + */ + for (i = first_fb_vc; i <= last_fb_vc; i++) { + if (con2fb_map[i] == idx) { + con2fb_map[i] = -1; + if (!search_fb_in_map(idx)) { + ret = con2fb_release_oldinfo(vc_cons[i].d, + info, NULL, i, + idx, 0); + if (ret) { + con2fb_map[i] = idx; + return ret; + } + } + } + } ret = fbcon_unbind(); + } return ret; } @@ -3556,8 +3552,9 @@ } } + do_fbcon_takeover(0); console_unlock(); - fbcon_takeover(0); + } } @@ -3587,8 +3584,10 @@ "no")); for (j = first_fb_vc; j <= last_fb_vc; j++) { - if (con2fb_map[j] == i) + if (con2fb_map[j] == i) { mapped = 1; + break; + } } if (mapped) { @@ -3601,6 +3600,7 @@ fbcon_del_cursor_timer(info); kfree(ops->cursor_src); + kfree(ops->cursor_state.mask); kfree(info->fbcon_par); info->fbcon_par = NULL; } @@ -3638,7 +3638,7 @@ return 0; } -module_init(fb_console_init); +fs_initcall(fb_console_init); #ifdef MODULE @@ -3661,8 +3661,8 @@ fbcon_deinit_device(); device_destroy(fb_class, MKDEV(0, 0)); fbcon_exit(); + do_unregister_con_driver(&fb_con); console_unlock(); - unregister_con_driver(&fb_con); } module_exit(fb_console_exit);