18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Unified handling of special chars.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *    Copyright IBM Corp. 2001
68c2ecf20Sopenharmony_ci *    Author(s): Fritz Elfert <felfert@millenux.com> <elfert@de.ibm.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/stddef.h>
118c2ecf20Sopenharmony_ci#include <asm/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/sysrq.h>
138c2ecf20Sopenharmony_ci#include <linux/ctype.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "ctrlchar.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#ifdef CONFIG_MAGIC_SYSRQ
188c2ecf20Sopenharmony_cistatic struct sysrq_work ctrlchar_sysrq;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic void
218c2ecf20Sopenharmony_cictrlchar_handle_sysrq(struct work_struct *work)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	struct sysrq_work *sysrq = container_of(work, struct sysrq_work, work);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	handle_sysrq(sysrq->key);
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_civoid schedule_sysrq_work(struct sysrq_work *sw)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	INIT_WORK(&sw->work, ctrlchar_handle_sysrq);
318c2ecf20Sopenharmony_ci	schedule_work(&sw->work);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci#endif
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/**
378c2ecf20Sopenharmony_ci * Check for special chars at start of input.
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * @param buf Console input buffer.
408c2ecf20Sopenharmony_ci * @param len Length of valid data in buffer.
418c2ecf20Sopenharmony_ci * @param tty The tty struct for this console.
428c2ecf20Sopenharmony_ci * @return CTRLCHAR_NONE, if nothing matched,
438c2ecf20Sopenharmony_ci *         CTRLCHAR_SYSRQ, if sysrq was encountered
448c2ecf20Sopenharmony_ci *         otherwise char to be inserted logically or'ed
458c2ecf20Sopenharmony_ci *         with CTRLCHAR_CTRL
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_ciunsigned int
488c2ecf20Sopenharmony_cictrlchar_handle(const unsigned char *buf, int len, struct tty_struct *tty)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	if ((len < 2) || (len > 3))
518c2ecf20Sopenharmony_ci		return CTRLCHAR_NONE;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	/* hat is 0xb1 in codepage 037 (US etc.) and thus */
548c2ecf20Sopenharmony_ci	/* converted to 0x5e in ascii ('^') */
558c2ecf20Sopenharmony_ci	if ((buf[0] != '^') && (buf[0] != '\252'))
568c2ecf20Sopenharmony_ci		return CTRLCHAR_NONE;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#ifdef CONFIG_MAGIC_SYSRQ
598c2ecf20Sopenharmony_ci	/* racy */
608c2ecf20Sopenharmony_ci	if (len == 3 && buf[1] == '-') {
618c2ecf20Sopenharmony_ci		ctrlchar_sysrq.key = buf[2];
628c2ecf20Sopenharmony_ci		schedule_sysrq_work(&ctrlchar_sysrq);
638c2ecf20Sopenharmony_ci		return CTRLCHAR_SYSRQ;
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci#endif
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (len != 2)
688c2ecf20Sopenharmony_ci		return CTRLCHAR_NONE;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	switch (tolower(buf[1])) {
718c2ecf20Sopenharmony_ci	case 'c':
728c2ecf20Sopenharmony_ci		return INTR_CHAR(tty) | CTRLCHAR_CTRL;
738c2ecf20Sopenharmony_ci	case 'd':
748c2ecf20Sopenharmony_ci		return EOF_CHAR(tty)  | CTRLCHAR_CTRL;
758c2ecf20Sopenharmony_ci	case 'z':
768c2ecf20Sopenharmony_ci		return SUSP_CHAR(tty) | CTRLCHAR_CTRL;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci	return CTRLCHAR_NONE;
798c2ecf20Sopenharmony_ci}
80