summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/ppc/8260_io/uart.c93
-rw-r--r--include/asm-ppc/cpm_8260.h20
2 files changed, 88 insertions, 25 deletions
diff --git a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c
index d76f8bb086b0..ce24ffc92541 100644
--- a/arch/ppc/8260_io/uart.c
+++ b/arch/ppc/8260_io/uart.c
@@ -50,6 +50,10 @@
#include <asm/cpm_8260.h>
#include <asm/irq.h>
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
+
#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h>
@@ -77,6 +81,14 @@ static char *serial_version = "0.02";
static struct tty_driver *serial_driver;
static int serial_console_setup(struct console *co, char *options);
+static void serial_console_write(struct console *c, const char *s,
+ unsigned count);
+static kdev_t serial_console_device(struct console *c);
+
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+static unsigned long break_pressed; /* break, really ... */
+#endif
+
/*
* Serial driver configuration section. Here are the various options:
*/
@@ -208,6 +220,15 @@ typedef struct serial_info {
cbd_t *tx_cur;
} ser_info_t;
+static struct console sercons = {
+ .name = "ttyS",
+ .write = serial_console_write,
+ .device = serial_console_device,
+ .setup = serial_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = CONFIG_SERIAL_CONSOLE_PORT,
+};
+
static void change_speed(ser_info_t *info);
static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -328,7 +349,7 @@ static _INLINE_ void rs_sched_event(ser_info_t *info,
schedule_work(&info->tqueue);
}
-static _INLINE_ void receive_chars(ser_info_t *info)
+static _INLINE_ void receive_chars(ser_info_t *info, struct pt_regs *regs)
{
struct tty_struct *tty = info->tty;
unsigned char ch, *cp;
@@ -450,6 +471,19 @@ static _INLINE_ void receive_chars(ser_info_t *info)
}
}
}
+
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ if (break_pressed && info->line == sercons.index) {
+ if (ch != 0 && time_before(jiffies,
+ break_pressed + HZ*5)) {
+ handle_sysrq(ch, regs, NULL, NULL);
+ break_pressed = 0;
+ goto ignore_char;
+ } else
+ break_pressed = 0;
+ }
+#endif
+
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
break;
@@ -458,6 +492,10 @@ static _INLINE_ void receive_chars(ser_info_t *info)
tty->flip.count++;
}
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ ignore_char:
+#endif
+
/* This BD is ready to be used again. Clear status.
* Get next BD.
*/
@@ -475,7 +513,36 @@ static _INLINE_ void receive_chars(ser_info_t *info)
schedule_delayed_work(&tty->flip.work, 1);
}
-static _INLINE_ void transmit_chars(ser_info_t *info)
+static _INLINE_ void receive_break(ser_info_t *info, struct pt_regs *regs)
+{
+ struct tty_struct *tty = info->tty;
+
+ info->state->icount.brk++;
+
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ if (info->line == sercons.index) {
+ if (!break_pressed) {
+ break_pressed = jiffies;
+ return;
+ } else
+ break_pressed = 0;
+ }
+#endif
+
+ /* Check to see if there is room in the tty buffer for
+ * the break. If not, we exit now, losing the break. FIXME
+ */
+ if ((tty->flip.count + 1) >= TTY_FLIPBUF_SIZE)
+ return;
+ *(tty->flip.flag_buf_ptr++) = TTY_BREAK;
+ *(tty->flip.char_buf_ptr++) = 0;
+ tty->flip.count++;
+
+ queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+
+static _INLINE_ void transmit_chars(ser_info_t *info, struct pt_regs *regs)
{
if (info->flags & TX_WAKEUP) {
@@ -575,19 +642,23 @@ static irqreturn_t rs_8xx_interrupt(int irq, void * dev_id, struct pt_regs * reg
if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx];
events = smcp->smc_smce;
+ if (events & SMCM_BRKE)
+ receive_break(info, regs);
if (events & SMCM_RX)
- receive_chars(info);
+ receive_chars(info, regs);
if (events & SMCM_TX)
- transmit_chars(info);
+ transmit_chars(info, regs);
smcp->smc_smce = events;
}
else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE];
events = sccp->scc_scce;
+ if (events & SMCM_BRKE)
+ receive_break(info, regs);
if (events & SCCM_RX)
- receive_chars(info);
+ receive_chars(info, regs);
if (events & SCCM_TX)
- transmit_chars(info);
+ transmit_chars(info, regs);
sccp->scc_scce = events;
}
@@ -2397,16 +2468,6 @@ static kdev_t serial_console_device(struct console *c)
return serial_driver;
}
-
-static struct console sercons = {
- .name = "ttyS",
- .write = serial_console_write,
- .device = serial_console_device,
- .setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = CONFIG_SERIAL_CONSOLE_PORT,
-};
-
/*
* Register console.
*/
diff --git a/include/asm-ppc/cpm_8260.h b/include/asm-ppc/cpm_8260.h
index 332ea70daef1..0afe638855fb 100644
--- a/include/asm-ppc/cpm_8260.h
+++ b/include/asm-ppc/cpm_8260.h
@@ -195,7 +195,7 @@ typedef struct smc_uart {
/* SMC uart mode register (Internal memory map).
*/
-#define SMCMR_REN ((ushort)0x0001)
+#define SMCMR_REN ((ushort)0x0001)
#define SMCMR_TEN ((ushort)0x0002)
#define SMCMR_DM ((ushort)0x000c)
#define SMCMR_SM_GCI ((ushort)0x0000)
@@ -212,10 +212,12 @@ typedef struct smc_uart {
/* SMC Event and Mask register.
*/
-#define SMCM_TXE ((unsigned char)0x10)
-#define SMCM_BSY ((unsigned char)0x04)
-#define SMCM_TX ((unsigned char)0x02)
-#define SMCM_RX ((unsigned char)0x01)
+#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */
+#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */
+#define SMCM_TXE ((unsigned char)0x10)
+#define SMCM_BSY ((unsigned char)0x04)
+#define SMCM_TX ((unsigned char)0x02)
+#define SMCM_RX ((unsigned char)0x01)
/* Baud rate generators.
*/
@@ -314,10 +316,10 @@ typedef struct smc_uart {
/* SCC Event and Mask register.
*/
-#define SCCM_TXE ((unsigned char)0x10)
-#define SCCM_BSY ((unsigned char)0x04)
-#define SCCM_TX ((unsigned char)0x02)
-#define SCCM_RX ((unsigned char)0x01)
+#define SCCM_TXE ((unsigned char)0x10)
+#define SCCM_BSY ((unsigned char)0x04)
+#define SCCM_TX ((unsigned char)0x02)
+#define SCCM_RX ((unsigned char)0x01)
typedef struct scc_param {
ushort scc_rbase; /* Rx Buffer descriptor base address */