cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

braille_console.c (7488B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Minimalistic braille device kernel support.
      4 *
      5 * By default, shows console messages on the braille device.
      6 * Pressing Insert switches to VC browsing.
      7 *
      8 *  Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.org>
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/moduleparam.h>
     14#include <linux/console.h>
     15#include <linux/notifier.h>
     16
     17#include <linux/selection.h>
     18#include <linux/vt_kern.h>
     19#include <linux/consolemap.h>
     20
     21#include <linux/keyboard.h>
     22#include <linux/kbd_kern.h>
     23#include <linux/input.h>
     24
     25MODULE_AUTHOR("samuel.thibault@ens-lyon.org");
     26MODULE_DESCRIPTION("braille device");
     27MODULE_LICENSE("GPL");
     28
     29/*
     30 * Braille device support part.
     31 */
     32
     33/* Emit various sounds */
     34static bool sound;
     35module_param(sound, bool, 0);
     36MODULE_PARM_DESC(sound, "emit sounds");
     37
     38static void beep(unsigned int freq)
     39{
     40	if (sound)
     41		kd_mksound(freq, HZ/10);
     42}
     43
     44/* mini console */
     45#define WIDTH 40
     46#define BRAILLE_KEY KEY_INSERT
     47static u16 console_buf[WIDTH];
     48static int console_cursor;
     49
     50/* mini view of VC */
     51static int vc_x, vc_y, lastvc_x, lastvc_y;
     52
     53/* show console ? (or show VC) */
     54static int console_show = 1;
     55/* pending newline ? */
     56static int console_newline = 1;
     57static int lastVC = -1;
     58
     59static struct console *braille_co;
     60
     61/* Very VisioBraille-specific */
     62static void braille_write(u16 *buf)
     63{
     64	static u16 lastwrite[WIDTH];
     65	unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
     66	u16 out;
     67	int i;
     68
     69	if (!braille_co)
     70		return;
     71
     72	if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
     73		return;
     74	memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
     75
     76#define SOH 1
     77#define STX 2
     78#define ETX 2
     79#define EOT 4
     80#define ENQ 5
     81	data[0] = STX;
     82	data[1] = '>';
     83	csum ^= '>';
     84	c = &data[2];
     85	for (i = 0; i < WIDTH; i++) {
     86		out = buf[i];
     87		if (out >= 0x100)
     88			out = '?';
     89		else if (out == 0x00)
     90			out = ' ';
     91		csum ^= out;
     92		if (out <= 0x05) {
     93			*c++ = SOH;
     94			out |= 0x40;
     95		}
     96		*c++ = out;
     97	}
     98
     99	if (csum <= 0x05) {
    100		*c++ = SOH;
    101		csum |= 0x40;
    102	}
    103	*c++ = csum;
    104	*c++ = ETX;
    105
    106	braille_co->write(braille_co, data, c - data);
    107}
    108
    109/* Follow the VC cursor*/
    110static void vc_follow_cursor(struct vc_data *vc)
    111{
    112	vc_x = vc->state.x - (vc->state.x % WIDTH);
    113	vc_y = vc->state.y;
    114	lastvc_x = vc->state.x;
    115	lastvc_y = vc->state.y;
    116}
    117
    118/* Maybe the VC cursor moved, if so follow it */
    119static void vc_maybe_cursor_moved(struct vc_data *vc)
    120{
    121	if (vc->state.x != lastvc_x || vc->state.y != lastvc_y)
    122		vc_follow_cursor(vc);
    123}
    124
    125/* Show portion of VC at vc_x, vc_y */
    126static void vc_refresh(struct vc_data *vc)
    127{
    128	u16 buf[WIDTH];
    129	int i;
    130
    131	for (i = 0; i < WIDTH; i++) {
    132		u16 glyph = screen_glyph(vc,
    133				2 * (vc_x + i) + vc_y * vc->vc_size_row);
    134		buf[i] = inverse_translate(vc, glyph, 1);
    135	}
    136	braille_write(buf);
    137}
    138
    139/*
    140 * Link to keyboard
    141 */
    142
    143static int keyboard_notifier_call(struct notifier_block *blk,
    144				  unsigned long code, void *_param)
    145{
    146	struct keyboard_notifier_param *param = _param;
    147	struct vc_data *vc = param->vc;
    148	int ret = NOTIFY_OK;
    149
    150	if (!param->down)
    151		return ret;
    152
    153	switch (code) {
    154	case KBD_KEYCODE:
    155		if (console_show) {
    156			if (param->value == BRAILLE_KEY) {
    157				console_show = 0;
    158				beep(880);
    159				vc_maybe_cursor_moved(vc);
    160				vc_refresh(vc);
    161				ret = NOTIFY_STOP;
    162			}
    163		} else {
    164			ret = NOTIFY_STOP;
    165			switch (param->value) {
    166			case KEY_INSERT:
    167				beep(440);
    168				console_show = 1;
    169				lastVC = -1;
    170				braille_write(console_buf);
    171				break;
    172			case KEY_LEFT:
    173				if (vc_x > 0) {
    174					vc_x -= WIDTH;
    175					if (vc_x < 0)
    176						vc_x = 0;
    177				} else if (vc_y >= 1) {
    178					beep(880);
    179					vc_y--;
    180					vc_x = vc->vc_cols-WIDTH;
    181				} else
    182					beep(220);
    183				break;
    184			case KEY_RIGHT:
    185				if (vc_x + WIDTH < vc->vc_cols) {
    186					vc_x += WIDTH;
    187				} else if (vc_y + 1 < vc->vc_rows) {
    188					beep(880);
    189					vc_y++;
    190					vc_x = 0;
    191				} else
    192					beep(220);
    193				break;
    194			case KEY_DOWN:
    195				if (vc_y + 1 < vc->vc_rows)
    196					vc_y++;
    197				else
    198					beep(220);
    199				break;
    200			case KEY_UP:
    201				if (vc_y >= 1)
    202					vc_y--;
    203				else
    204					beep(220);
    205				break;
    206			case KEY_HOME:
    207				vc_follow_cursor(vc);
    208				break;
    209			case KEY_PAGEUP:
    210				vc_x = 0;
    211				vc_y = 0;
    212				break;
    213			case KEY_PAGEDOWN:
    214				vc_x = 0;
    215				vc_y = vc->vc_rows-1;
    216				break;
    217			default:
    218				ret = NOTIFY_OK;
    219				break;
    220			}
    221			if (ret == NOTIFY_STOP)
    222				vc_refresh(vc);
    223		}
    224		break;
    225	case KBD_POST_KEYSYM:
    226	{
    227		unsigned char type = KTYP(param->value) - 0xf0;
    228
    229		if (type == KT_SPEC) {
    230			unsigned char val = KVAL(param->value);
    231			int on_off = -1;
    232
    233			switch (val) {
    234			case KVAL(K_CAPS):
    235				on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
    236				break;
    237			case KVAL(K_NUM):
    238				on_off = vt_get_leds(fg_console, VC_NUMLOCK);
    239				break;
    240			case KVAL(K_HOLD):
    241				on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
    242				break;
    243			}
    244			if (on_off == 1)
    245				beep(880);
    246			else if (on_off == 0)
    247				beep(440);
    248		}
    249	}
    250		break;
    251	case KBD_UNBOUND_KEYCODE:
    252	case KBD_UNICODE:
    253	case KBD_KEYSYM:
    254		/* Unused */
    255		break;
    256	}
    257	return ret;
    258}
    259
    260static struct notifier_block keyboard_notifier_block = {
    261	.notifier_call = keyboard_notifier_call,
    262};
    263
    264static int vt_notifier_call(struct notifier_block *blk,
    265			    unsigned long code, void *_param)
    266{
    267	struct vt_notifier_param *param = _param;
    268	struct vc_data *vc = param->vc;
    269
    270	switch (code) {
    271	case VT_ALLOCATE:
    272		break;
    273	case VT_DEALLOCATE:
    274		break;
    275	case VT_WRITE:
    276	{
    277		unsigned char c = param->c;
    278
    279		if (vc->vc_num != fg_console)
    280			break;
    281		switch (c) {
    282		case '\b':
    283		case 127:
    284			if (console_cursor > 0) {
    285				console_cursor--;
    286				console_buf[console_cursor] = ' ';
    287			}
    288			break;
    289		case '\n':
    290		case '\v':
    291		case '\f':
    292		case '\r':
    293			console_newline = 1;
    294			break;
    295		case '\t':
    296			c = ' ';
    297			fallthrough;
    298		default:
    299			if (c < 32)
    300				/* Ignore other control sequences */
    301				break;
    302			if (console_newline) {
    303				memset(console_buf, 0, sizeof(console_buf));
    304				console_cursor = 0;
    305				console_newline = 0;
    306			}
    307			if (console_cursor == WIDTH)
    308				memmove(console_buf, &console_buf[1],
    309					(WIDTH-1) * sizeof(*console_buf));
    310			else
    311				console_cursor++;
    312			console_buf[console_cursor-1] = c;
    313			break;
    314		}
    315		if (console_show)
    316			braille_write(console_buf);
    317		else {
    318			vc_maybe_cursor_moved(vc);
    319			vc_refresh(vc);
    320		}
    321		break;
    322	}
    323	case VT_UPDATE:
    324		/* Maybe a VT switch, flush */
    325		if (console_show) {
    326			if (vc->vc_num != lastVC) {
    327				lastVC = vc->vc_num;
    328				memset(console_buf, 0, sizeof(console_buf));
    329				console_cursor = 0;
    330				braille_write(console_buf);
    331			}
    332		} else {
    333			vc_maybe_cursor_moved(vc);
    334			vc_refresh(vc);
    335		}
    336		break;
    337	}
    338	return NOTIFY_OK;
    339}
    340
    341static struct notifier_block vt_notifier_block = {
    342	.notifier_call = vt_notifier_call,
    343};
    344
    345/*
    346 * Called from printk.c when console=brl is given
    347 */
    348
    349int braille_register_console(struct console *console, int index,
    350		char *console_options, char *braille_options)
    351{
    352	int ret;
    353
    354	if (!console_options)
    355		/* Only support VisioBraille for now */
    356		console_options = "57600o8";
    357	if (braille_co)
    358		return -ENODEV;
    359	if (console->setup) {
    360		ret = console->setup(console, console_options);
    361		if (ret != 0)
    362			return ret;
    363	}
    364	console->flags |= CON_ENABLED;
    365	console->index = index;
    366	braille_co = console;
    367	register_keyboard_notifier(&keyboard_notifier_block);
    368	register_vt_notifier(&vt_notifier_block);
    369	return 1;
    370}
    371
    372int braille_unregister_console(struct console *console)
    373{
    374	if (braille_co != console)
    375		return -EINVAL;
    376	unregister_keyboard_notifier(&keyboard_notifier_block);
    377	unregister_vt_notifier(&vt_notifier_block);
    378	braille_co = NULL;
    379	return 1;
    380}