Commit 5cc974f5 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390 update (27/27): control characters.

Replace IMMEDIATE_BH bottom half by tasklets in helper functions for
console control characters. Fix a race condition and make it look nicer.
parent 2b46c627
......@@ -455,7 +455,7 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
if ((raw = req->info) == NULL)
return; /* That shouldn't happen ... */
if (req->type == RAW3215_READ && raw->tty != NULL) {
char *cchar;
unsigned int cchar;
tty = raw->tty;
count = 160 - req->residual;
......@@ -467,14 +467,19 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
if (count >= TTY_FLIPBUF_SIZE - tty->flip.count)
count = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
EBCASC(raw->inbuf, count);
if ((cchar = ctrlchar_handle(raw->inbuf, count, tty))) {
if (cchar == (char *)-1)
goto in_out;
cchar = ctrlchar_handle(raw->inbuf, count, tty);
switch (cchar & CTRLCHAR_MASK) {
case CTRLCHAR_SYSRQ:
break;
case CTRLCHAR_CTRL:
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
*tty->flip.char_buf_ptr++ = *cchar;
*tty->flip.char_buf_ptr++ = cchar;
tty_flip_buffer_push(raw->tty);
} else {
break;
case CTRLCHAR_NONE:
memcpy(tty->flip.char_buf_ptr,
raw->inbuf, count);
if (count < 2 ||
......@@ -491,12 +496,13 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
tty->flip.flag_buf_ptr += count;
tty->flip.count += count;
tty_flip_buffer_push(raw->tty);
break;
}
} else if (req->type == RAW3215_WRITE) {
raw->count -= req->len;
raw->written -= req->len;
}
in_out:
raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req);
/* check for empty wait */
......@@ -1095,8 +1101,6 @@ void __init con3215_init(void)
raw3215_freelist = req;
}
ctrlchar_init();
#ifdef CONFIG_TN3215_CONSOLE
raw3215[0] = raw = (raw3215_info *)
alloc_bootmem_low(sizeof(raw3215_info));
......
......@@ -8,39 +8,27 @@
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/tty.h>
#include <linux/interrupt.h>
#include <linux/stddef.h>
#include <linux/sysrq.h>
#include <linux/ctype.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
#include <asm/cpcmd.h>
#include <asm/irq.h>
#include "ctrlchar.h"
#ifdef CONFIG_MAGIC_SYSRQ
static int ctrlchar_sysrq_key;
static struct tq_struct ctrlchar_tq;
static void
ctrlchar_handle_sysrq(struct tty_struct *tty) {
ctrlchar_handle_sysrq(void *tty)
{
handle_sysrq(ctrlchar_sysrq_key, NULL, tty);
}
#endif
void ctrlchar_init(void) {
#ifdef CONFIG_MAGIC_SYSRQ
static int init_done = 0;
if (init_done++)
return;
INIT_LIST_HEAD(&ctrlchar_tq.list);
ctrlchar_tq.sync = 0;
ctrlchar_tq.routine = (void (*)(void *)) ctrlchar_handle_sysrq;
static struct tq_struct ctrlchar_tq = {
.list = LIST_HEAD_INIT(ctrlchar_tq.list),
.routine = ctrlchar_handle_sysrq,
};
#endif
}
/**
* Check for special chars at start of input.
......@@ -48,49 +36,42 @@ void ctrlchar_init(void) {
* @param buf Console input buffer.
* @param len Length of valid data in buffer.
* @param tty The tty struct for this console.
* @return NULL, if nothing matched, (char *)-1, if buffer contents
* should be ignored, otherwise pointer to char to be inserted.
* @return CTRLCHAR_NONE, if nothing matched,
* CTRLCHAR_SYSRQ, if sysrq was encountered
* otherwise char to be inserted logically or'ed
* with CTRLCHAR_CTRL
*/
char *ctrlchar_handle(const char *buf, int len, struct tty_struct *tty) {
static char ret;
unsigned int
ctrlchar_handle(const char *buf, int len, struct tty_struct *tty)
{
if ((len < 2) || (len > 3))
return NULL;
return CTRLCHAR_NONE;
/* hat is 0xb1 in codepage 037 (US etc.) and thus */
/* converted to 0x5e in ascii ('^') */
if ((buf[0] != '^') && (buf[0] != '\252'))
return NULL;
switch (buf[1]) {
return CTRLCHAR_NONE;
#ifdef CONFIG_MAGIC_SYSRQ
case '-':
if (len == 3) {
/* racy */
if (len == 3 && buf[1] == '-') {
ctrlchar_sysrq_key = buf[2];
ctrlchar_tq.data = tty;
queue_task(&ctrlchar_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
return (char *)-1;
schedule_task(&ctrlchar_tq);
return CTRLCHAR_SYSRQ;
}
break;
#endif
if (len != 2)
return CTRLCHAR_NONE;
switch (tolower(buf[1])) {
case 'c':
if (len == 2) {
ret = INTR_CHAR(tty);
return &ret;
}
break;
return INTR_CHAR(tty) | CTRLCHAR_CTRL;
case 'd':
if (len == 2) {
ret = EOF_CHAR(tty);
return &ret;
}
break;
return EOF_CHAR(tty) | CTRLCHAR_CTRL;
case 'z':
if (len == 2) {
ret = SUSP_CHAR(tty);
return &ret;
}
break;
return SUSP_CHAR(tty) | CTRLCHAR_CTRL;
}
return NULL;
return CTRLCHAR_NONE;
}
......@@ -7,9 +7,14 @@
*
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/tty.h>
extern void ctrlchar_init(void);
extern char *ctrlchar_handle(const char *buf, int len, struct tty_struct *tty);
extern unsigned int
ctrlchar_handle(const char *buf, int len, struct tty_struct *tty);
#define CTRLCHAR_NONE (1 << 8)
#define CTRLCHAR_CTRL (2 << 8)
#define CTRLCHAR_SYSRQ (3 << 8)
#define CTRLCHAR_MASK (~0xffu)
......@@ -188,15 +188,19 @@ hwc_tty_input (unsigned char *buf, unsigned int count)
struct tty_struct *tty = hwc_tty_data.tty;
if (tty != NULL) {
char *cchar;
if ((cchar = ctrlchar_handle (buf, count, tty))) {
if (cchar == (char *) -1)
unsigned int cchar = ctrlchar_handle(buf, count, tty);
switch (cchar & CTRLCHAR_MASK) {
case CTRLCHAR_SYSRQ:
return;
case CTRLCHAR_CTRL:
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
*tty->flip.char_buf_ptr++ = *cchar;
} else {
*tty->flip.char_buf_ptr++ = cchar;
break;
case CTRLCHAR_NONE:
memcpy (tty->flip.char_buf_ptr, buf, count);
if (count < 2 || (
strncmp (buf + count - 2, "^n", 2) ||
......@@ -209,6 +213,7 @@ hwc_tty_input (unsigned char *buf, unsigned int count)
tty->flip.char_buf_ptr += count;
tty->flip.flag_buf_ptr += count;
tty->flip.count += count;
break;
}
tty_flip_buffer_push (tty);
hwc_tty_wake_up ();
......@@ -221,8 +226,6 @@ hwc_tty_init (void)
if (!CONSOLE_IS_HWC)
return;
ctrlchar_init ();
memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment