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