diff options
| -rw-r--r-- | arch/ppc/8260_io/uart.c | 93 | ||||
| -rw-r--r-- | include/asm-ppc/cpm_8260.h | 20 |
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 */ |
