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(nh: &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(nh: &dummycon_output_nh, nb); |
51 | } |
52 | |
53 | static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, |
54 | unsigned int x) |
55 | { |
56 | WARN_CONSOLE_UNLOCKED(); |
57 | |
58 | dummycon_putc_called = true; |
59 | raw_notifier_call_chain(nh: &dummycon_output_nh, val: 0, NULL); |
60 | } |
61 | |
62 | static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, |
63 | unsigned int ypos, unsigned int xpos) |
64 | { |
65 | unsigned int i; |
66 | |
67 | if (!dummycon_putc_called) { |
68 | /* Ignore erases */ |
69 | for (i = 0 ; i < count; i++) { |
70 | if (s[i] != vc->vc_video_erase_char) |
71 | break; |
72 | } |
73 | if (i == count) |
74 | return; |
75 | |
76 | dummycon_putc_called = true; |
77 | } |
78 | |
79 | raw_notifier_call_chain(nh: &dummycon_output_nh, val: 0, NULL); |
80 | } |
81 | |
82 | static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, |
83 | bool mode_switch) |
84 | { |
85 | /* Redraw, so that we get putc(s) for output done while blanked */ |
86 | return true; |
87 | } |
88 | #else |
89 | static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, |
90 | unsigned int x) { } |
91 | static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, |
92 | unsigned int ypos, unsigned int xpos) { } |
93 | static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, |
94 | bool mode_switch) |
95 | { |
96 | return false; |
97 | } |
98 | #endif |
99 | |
100 | static const char *dummycon_startup(void) |
101 | { |
102 | return "dummy device" ; |
103 | } |
104 | |
105 | static void dummycon_init(struct vc_data *vc, bool init) |
106 | { |
107 | vc->vc_can_do_color = 1; |
108 | if (init) { |
109 | vc->vc_cols = DUMMY_COLUMNS; |
110 | vc->vc_rows = DUMMY_ROWS; |
111 | } else |
112 | vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS); |
113 | } |
114 | |
115 | static void dummycon_deinit(struct vc_data *vc) { } |
116 | static void dummycon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, |
117 | unsigned int width) { } |
118 | static void dummycon_cursor(struct vc_data *vc, bool enable) { } |
119 | |
120 | static bool dummycon_scroll(struct vc_data *vc, unsigned int top, |
121 | unsigned int bottom, enum con_scroll dir, |
122 | unsigned int lines) |
123 | { |
124 | return false; |
125 | } |
126 | |
127 | static bool dummycon_switch(struct vc_data *vc) |
128 | { |
129 | return false; |
130 | } |
131 | |
132 | /* |
133 | * The console `switch' structure for the dummy console |
134 | * |
135 | * Most of the operations are dummies. |
136 | */ |
137 | |
138 | const struct consw dummy_con = { |
139 | .owner = THIS_MODULE, |
140 | .con_startup = dummycon_startup, |
141 | .con_init = dummycon_init, |
142 | .con_deinit = dummycon_deinit, |
143 | .con_clear = dummycon_clear, |
144 | .con_putc = dummycon_putc, |
145 | .con_putcs = dummycon_putcs, |
146 | .con_cursor = dummycon_cursor, |
147 | .con_scroll = dummycon_scroll, |
148 | .con_switch = dummycon_switch, |
149 | .con_blank = dummycon_blank, |
150 | }; |
151 | EXPORT_SYMBOL_GPL(dummy_con); |
152 | |