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