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 */ 32 static RAW_NOTIFIER_HEAD(dummycon_output_nh); 33 static bool dummycon_putc_called; 34 35 void 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 45 void 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 52 static 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 60 static 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 80 static 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 86 static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } 87 static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, 88 int count, int ypos, int xpos) { } 89 static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) 90 { 91 return 0; 92 } 93 #endif 94 95 static const char *dummycon_startup(void) 96 { 97 return "dummy device"; 98 } 99 100 static 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 110 static void dummycon_deinit(struct vc_data *vc) { } 111 static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height, 112 int width) { } 113 static void dummycon_cursor(struct vc_data *vc, int mode) { } 114 115 static 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 122 static 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 133 const 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 }; 146 EXPORT_SYMBOL_GPL(dummy_con); 147