dummycon.c (3578B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * linux/drivers/video/dummycon.c -- A dummy console driver 4 * 5 * To be used if there's no other console driver (e.g. for plain VGA text) 6 * available, usually until fbcon takes console over. 7 */ 8 9#include <linux/types.h> 10#include <linux/kdev_t.h> 11#include <linux/console.h> 12#include <linux/vt_kern.h> 13#include <linux/screen_info.h> 14#include <linux/init.h> 15#include <linux/module.h> 16 17/* 18 * Dummy console driver 19 */ 20 21#if defined(__arm__) 22#define DUMMY_COLUMNS screen_info.orig_video_cols 23#define DUMMY_ROWS screen_info.orig_video_lines 24#else 25/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */ 26#define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS 27#define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS 28#endif 29 30#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER 31/* These are both protected by the console_lock */ 32static RAW_NOTIFIER_HEAD(dummycon_output_nh); 33static bool dummycon_putc_called; 34 35void dummycon_register_output_notifier(struct notifier_block *nb) 36{ 37 WARN_CONSOLE_UNLOCKED(); 38 39 raw_notifier_chain_register(&dummycon_output_nh, nb); 40 41 if (dummycon_putc_called) 42 nb->notifier_call(nb, 0, NULL); 43} 44 45void dummycon_unregister_output_notifier(struct notifier_block *nb) 46{ 47 WARN_CONSOLE_UNLOCKED(); 48 49 raw_notifier_chain_unregister(&dummycon_output_nh, nb); 50} 51 52static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) 53{ 54 WARN_CONSOLE_UNLOCKED(); 55 56 dummycon_putc_called = true; 57 raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); 58} 59 60static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, 61 int count, int ypos, int xpos) 62{ 63 int i; 64 65 if (!dummycon_putc_called) { 66 /* Ignore erases */ 67 for (i = 0 ; i < count; i++) { 68 if (s[i] != vc->vc_video_erase_char) 69 break; 70 } 71 if (i == count) 72 return; 73 74 dummycon_putc_called = true; 75 } 76 77 raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); 78} 79 80static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) 81{ 82 /* Redraw, so that we get putc(s) for output done while blanked */ 83 return 1; 84} 85#else 86static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } 87static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, 88 int count, int ypos, int xpos) { } 89static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) 90{ 91 return 0; 92} 93#endif 94 95static const char *dummycon_startup(void) 96{ 97 return "dummy device"; 98} 99 100static void dummycon_init(struct vc_data *vc, int init) 101{ 102 vc->vc_can_do_color = 1; 103 if (init) { 104 vc->vc_cols = DUMMY_COLUMNS; 105 vc->vc_rows = DUMMY_ROWS; 106 } else 107 vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS); 108} 109 110static void dummycon_deinit(struct vc_data *vc) { } 111static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height, 112 int width) { } 113static void dummycon_cursor(struct vc_data *vc, int mode) { } 114 115static bool dummycon_scroll(struct vc_data *vc, unsigned int top, 116 unsigned int bottom, enum con_scroll dir, 117 unsigned int lines) 118{ 119 return false; 120} 121 122static int dummycon_switch(struct vc_data *vc) 123{ 124 return 0; 125} 126 127/* 128 * The console `switch' structure for the dummy console 129 * 130 * Most of the operations are dummies. 131 */ 132 133const struct consw dummy_con = { 134 .owner = THIS_MODULE, 135 .con_startup = dummycon_startup, 136 .con_init = dummycon_init, 137 .con_deinit = dummycon_deinit, 138 .con_clear = dummycon_clear, 139 .con_putc = dummycon_putc, 140 .con_putcs = dummycon_putcs, 141 .con_cursor = dummycon_cursor, 142 .con_scroll = dummycon_scroll, 143 .con_switch = dummycon_switch, 144 .con_blank = dummycon_blank, 145}; 146EXPORT_SYMBOL_GPL(dummy_con);