Commit 54ce9a20 authored by Tom Rini's avatar Tom Rini

PPC32: Add Magic SysRq support to the MPC8260 platforms.

From Wade Farnsworth <wfarnsworth@mvista.com>.
parent 63360427
...@@ -50,6 +50,10 @@ ...@@ -50,6 +50,10 @@
#include <asm/cpm_8260.h> #include <asm/cpm_8260.h>
#include <asm/irq.h> #include <asm/irq.h>
#ifdef CONFIG_MAGIC_SYSRQ
#include <linux/sysrq.h>
#endif
#ifdef CONFIG_SERIAL_CONSOLE #ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h> #include <linux/console.h>
...@@ -77,6 +81,14 @@ static char *serial_version = "0.02"; ...@@ -77,6 +81,14 @@ static char *serial_version = "0.02";
static struct tty_driver *serial_driver; static struct tty_driver *serial_driver;
static int serial_console_setup(struct console *co, char *options); 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: * Serial driver configuration section. Here are the various options:
*/ */
...@@ -208,6 +220,15 @@ typedef struct serial_info { ...@@ -208,6 +220,15 @@ typedef struct serial_info {
cbd_t *tx_cur; cbd_t *tx_cur;
} ser_info_t; } 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 change_speed(ser_info_t *info);
static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout); 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, ...@@ -328,7 +349,7 @@ static _INLINE_ void rs_sched_event(ser_info_t *info,
schedule_work(&info->tqueue); 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; struct tty_struct *tty = info->tty;
unsigned char ch, *cp; unsigned char ch, *cp;
...@@ -450,6 +471,19 @@ static _INLINE_ void receive_chars(ser_info_t *info) ...@@ -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) if (tty->flip.count >= TTY_FLIPBUF_SIZE)
break; break;
...@@ -458,6 +492,10 @@ static _INLINE_ void receive_chars(ser_info_t *info) ...@@ -458,6 +492,10 @@ static _INLINE_ void receive_chars(ser_info_t *info)
tty->flip.count++; 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. /* This BD is ready to be used again. Clear status.
* Get next BD. * Get next BD.
*/ */
...@@ -475,7 +513,36 @@ static _INLINE_ void receive_chars(ser_info_t *info) ...@@ -475,7 +513,36 @@ static _INLINE_ void receive_chars(ser_info_t *info)
schedule_delayed_work(&tty->flip.work, 1); 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) { if (info->flags & TX_WAKEUP) {
...@@ -575,19 +642,23 @@ static irqreturn_t rs_8xx_interrupt(int irq, void * dev_id, struct pt_regs * reg ...@@ -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) { if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx]; smcp = &immr->im_smc[idx];
events = smcp->smc_smce; events = smcp->smc_smce;
if (events & SMCM_BRKE)
receive_break(info, regs);
if (events & SMCM_RX) if (events & SMCM_RX)
receive_chars(info); receive_chars(info, regs);
if (events & SMCM_TX) if (events & SMCM_TX)
transmit_chars(info); transmit_chars(info, regs);
smcp->smc_smce = events; smcp->smc_smce = events;
} }
else { else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE]; sccp = &immr->im_scc[idx - SCC_IDX_BASE];
events = sccp->scc_scce; events = sccp->scc_scce;
if (events & SMCM_BRKE)
receive_break(info, regs);
if (events & SCCM_RX) if (events & SCCM_RX)
receive_chars(info); receive_chars(info, regs);
if (events & SCCM_TX) if (events & SCCM_TX)
transmit_chars(info); transmit_chars(info, regs);
sccp->scc_scce = events; sccp->scc_scce = events;
} }
...@@ -2397,16 +2468,6 @@ static kdev_t serial_console_device(struct console *c) ...@@ -2397,16 +2468,6 @@ static kdev_t serial_console_device(struct console *c)
return serial_driver; 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. * Register console.
*/ */
......
...@@ -212,6 +212,8 @@ typedef struct smc_uart { ...@@ -212,6 +212,8 @@ typedef struct smc_uart {
/* SMC Event and Mask register. /* SMC Event and Mask register.
*/ */
#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_TXE ((unsigned char)0x10)
#define SMCM_BSY ((unsigned char)0x04) #define SMCM_BSY ((unsigned char)0x04)
#define SMCM_TX ((unsigned char)0x02) #define SMCM_TX ((unsigned char)0x02)
......
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