162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/drivers/video/dummycon.c -- A dummy console driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  To be used if there's no other console driver (e.g. for plain VGA text)
662306a36Sopenharmony_ci *  available, usually until fbcon takes console over.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/types.h>
1062306a36Sopenharmony_ci#include <linux/kdev_t.h>
1162306a36Sopenharmony_ci#include <linux/console.h>
1262306a36Sopenharmony_ci#include <linux/vt_kern.h>
1362306a36Sopenharmony_ci#include <linux/screen_info.h>
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci *  Dummy console driver
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#if defined(__arm__)
2262306a36Sopenharmony_ci#define DUMMY_COLUMNS	screen_info.orig_video_cols
2362306a36Sopenharmony_ci#define DUMMY_ROWS	screen_info.orig_video_lines
2462306a36Sopenharmony_ci#else
2562306a36Sopenharmony_ci/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */
2662306a36Sopenharmony_ci#define DUMMY_COLUMNS	CONFIG_DUMMY_CONSOLE_COLUMNS
2762306a36Sopenharmony_ci#define DUMMY_ROWS	CONFIG_DUMMY_CONSOLE_ROWS
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
3162306a36Sopenharmony_ci/* These are both protected by the console_lock */
3262306a36Sopenharmony_cistatic RAW_NOTIFIER_HEAD(dummycon_output_nh);
3362306a36Sopenharmony_cistatic bool dummycon_putc_called;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_civoid dummycon_register_output_notifier(struct notifier_block *nb)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	WARN_CONSOLE_UNLOCKED();
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	raw_notifier_chain_register(&dummycon_output_nh, nb);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (dummycon_putc_called)
4262306a36Sopenharmony_ci		nb->notifier_call(nb, 0, NULL);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_civoid dummycon_unregister_output_notifier(struct notifier_block *nb)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	WARN_CONSOLE_UNLOCKED();
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	raw_notifier_chain_unregister(&dummycon_output_nh, nb);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	WARN_CONSOLE_UNLOCKED();
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	dummycon_putc_called = true;
5762306a36Sopenharmony_ci	raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
6162306a36Sopenharmony_ci			   int count, int ypos, int xpos)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	int i;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (!dummycon_putc_called) {
6662306a36Sopenharmony_ci		/* Ignore erases */
6762306a36Sopenharmony_ci		for (i = 0 ; i < count; i++) {
6862306a36Sopenharmony_ci			if (s[i] != vc->vc_video_erase_char)
6962306a36Sopenharmony_ci				break;
7062306a36Sopenharmony_ci		}
7162306a36Sopenharmony_ci		if (i == count)
7262306a36Sopenharmony_ci			return;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		dummycon_putc_called = true;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	/* Redraw, so that we get putc(s) for output done while blanked */
8362306a36Sopenharmony_ci	return 1;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci#else
8662306a36Sopenharmony_cistatic void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
8762306a36Sopenharmony_cistatic void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
8862306a36Sopenharmony_ci			   int count, int ypos, int xpos) { }
8962306a36Sopenharmony_cistatic int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci#endif
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic const char *dummycon_startup(void)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci    return "dummy device";
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void dummycon_init(struct vc_data *vc, int init)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci    vc->vc_can_do_color = 1;
10362306a36Sopenharmony_ci    if (init) {
10462306a36Sopenharmony_ci	vc->vc_cols = DUMMY_COLUMNS;
10562306a36Sopenharmony_ci	vc->vc_rows = DUMMY_ROWS;
10662306a36Sopenharmony_ci    } else
10762306a36Sopenharmony_ci	vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic void dummycon_deinit(struct vc_data *vc) { }
11162306a36Sopenharmony_cistatic void dummycon_clear(struct vc_data *vc, int sy, int sx, int height,
11262306a36Sopenharmony_ci			   int width) { }
11362306a36Sopenharmony_cistatic void dummycon_cursor(struct vc_data *vc, int mode) { }
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic bool dummycon_scroll(struct vc_data *vc, unsigned int top,
11662306a36Sopenharmony_ci			    unsigned int bottom, enum con_scroll dir,
11762306a36Sopenharmony_ci			    unsigned int lines)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	return false;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int dummycon_switch(struct vc_data *vc)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/*
12862306a36Sopenharmony_ci *  The console `switch' structure for the dummy console
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci *  Most of the operations are dummies.
13162306a36Sopenharmony_ci */
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciconst struct consw dummy_con = {
13462306a36Sopenharmony_ci	.owner =		THIS_MODULE,
13562306a36Sopenharmony_ci	.con_startup =	dummycon_startup,
13662306a36Sopenharmony_ci	.con_init =		dummycon_init,
13762306a36Sopenharmony_ci	.con_deinit =	dummycon_deinit,
13862306a36Sopenharmony_ci	.con_clear =	dummycon_clear,
13962306a36Sopenharmony_ci	.con_putc =		dummycon_putc,
14062306a36Sopenharmony_ci	.con_putcs =	dummycon_putcs,
14162306a36Sopenharmony_ci	.con_cursor =	dummycon_cursor,
14262306a36Sopenharmony_ci	.con_scroll =	dummycon_scroll,
14362306a36Sopenharmony_ci	.con_switch =	dummycon_switch,
14462306a36Sopenharmony_ci	.con_blank =	dummycon_blank,
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dummy_con);
147