--- zzzz-none-000/linux-2.4.17/drivers/char/sh-sci.c 2001-10-15 20:36:48.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/drivers/char/sh-sci.c 2004-11-24 13:23:20.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: sh-sci.c,v 1.40 2000/04/15 06:57:29 gniibe Exp $ +/* $Id: sh-sci.c,v 1.1.1.1 2003/06/23 22:18:26 jharrell Exp $ * * linux/drivers/char/sh-sci.c * @@ -32,7 +32,7 @@ #include #include #include -#ifdef CONFIG_SERIAL_CONSOLE +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SH_KGDB_CONSOLE) #include #endif @@ -50,11 +50,31 @@ #include "sh-sci.h" +#ifdef CONFIG_SH_KGDB +#include + +int kgdb_sci_setup(void); +static int kgdb_get_char(struct sci_port *port); +static void kgdb_put_char(struct sci_port *port, char c); +static void kgdb_handle_error(struct sci_port *port); +static struct sci_port *kgdb_sci_port; + +#ifdef CONFIG_SH_KGDB_CONSOLE +static struct console kgdbcons; +void __init kgdb_console_init(void); +#endif /* CONFIG_SH_KGDB_CONSOLE */ + +#endif /* CONFIG_SH_KGDB */ + #ifdef CONFIG_SERIAL_CONSOLE static struct console sercons; static struct sci_port* sercons_port=0; static int sercons_baud; -#endif +#ifdef CONFIG_MAGIC_SYSRQ +#include +static int break_pressed; +#endif /* CONFIG_MAGIC_SYSRQ */ +#endif /* CONFIG_SERIAL_CONSOLE */ /* Function prototypes */ static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag); @@ -114,7 +134,7 @@ } #endif -#ifdef CONFIG_SH_STANDARD_BIOS +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) static void handle_error(struct sci_port *port) { /* Clear error flags */ @@ -156,7 +176,7 @@ return hexchars[x & 0xf]; } -#endif +#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ /* * Send the packet in buffer. The host gets one chance to read it. @@ -168,13 +188,22 @@ { int i; const unsigned char *p = buffer; -#ifdef CONFIG_SH_STANDARD_BIOS + +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) int checksum; + int usegdb=0; +#ifdef CONFIG_SH_STANDARD_BIOS /* This call only does a trap the first time it is * called, and so is safe to do here unconditionally */ - if (sh_bios_in_gdb_mode()) { + usegdb |= sh_bios_in_gdb_mode(); +#endif +#ifdef CONFIG_SH_KGDB + usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port)); +#endif + + if (usegdb) { /* $#. */ do { unsigned char c; @@ -197,15 +226,101 @@ put_char(port, lowhex(checksum)); } while (get_char(port) != '+'); } else -#endif +#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ for (i=0; i txroom) count = txroom; - /* Don't copy pas the end of the source buffer */ + /* Don't copy past the end of the source buffer */ if (count > SERIAL_XMIT_SIZE - port->gs.xmit_tail) count = SERIAL_XMIT_SIZE - port->gs.xmit_tail; @@ -511,7 +626,11 @@ restore_flags(flags); } -static inline void sci_receive_chars(struct sci_port *port) +/* On SH3, SCIF may read end-of-break as a space->mark char */ +#define STEPFN(c) ({int __c=(c); (((__c-1)|(__c)) == -1); }) + +static inline void sci_receive_chars(struct sci_port *port, + struct pt_regs *regs) { int i, count; struct tty_struct *tty; @@ -534,7 +653,7 @@ if (tty->flip.count + count > TTY_FLIPBUF_SIZE) count = TTY_FLIPBUF_SIZE - tty->flip.count; - /* If for one reason or another, we can't copy more data, we're done! */ + /* If for any reason we can't copy more data, we're done! */ if (count == 0) break; @@ -543,8 +662,43 @@ tty->flip.flag_buf_ptr[0] = TTY_NORMAL; } else { for (i=0; iflip.char_buf_ptr[i] = sci_in(port, SCxRDR); + char c = sci_in(port, SCxRDR); status = sci_in(port, SCxSR); +#if defined(__SH3__) + /* Skip "chars" during break */ + if (port->break_flag) { + if ((c == 0) && + (status & SCxSR_FER(port))) { + count--; i--; + continue; + } + /* Nonzero => end-of-break */ + dprintk("scif: debounce<%02x>\n", c); + port->break_flag = 0; + if (STEPFN(c)) { + count--; i--; + continue; + } + } +#endif /* __SH3__ */ +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (break_pressed && (port == sercons_port)) { + if (c != 0 && + time_before(jiffies, + break_pressed + HZ*5)) { + handle_sysrq(c, regs, + NULL, NULL); + break_pressed = 0; + count--; i--; + continue; + } else if (c != 0) { + break_pressed = 0; + } + } +#endif /* CONFIG_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */ + + /* Store data and status */ + tty->flip.char_buf_ptr[i] = c; if (status&SCxSR_FER(port)) { tty->flip.flag_buf_ptr[i] = TTY_FRAME; dprintk("sci: frame error\n"); @@ -624,11 +778,29 @@ struct tty_struct *tty = port->gs.tty; if (status&SCxSR_BRK(port) && tty->flip.countbreak_flag) + goto break_continue; + port->break_flag = 1; +#endif +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (port == sercons_port) { + if (break_pressed == 0) { + break_pressed = jiffies; + dprintk("sci: implied sysrq\n"); + goto break_continue; + } + /* Double break implies a real break */ + break_pressed = 0; + } +#endif /* Notify of BREAK */ copied++; *tty->flip.flag_buf_ptr++ = TTY_BREAK; dprintk("sci: BREAK detected\n"); } + break_continue: #if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) /* XXX: Handle SCIF overrun error */ @@ -656,7 +828,7 @@ if (port->gs.flags & GS_ACTIVE) if (!(port->gs.flags & SCI_RX_THROTTLE)) { - sci_receive_chars(port); + sci_receive_chars(port, regs); return; } sci_disable_rx_interrupts(port); @@ -827,6 +999,7 @@ port->event = 0; port->tqueue.routine = do_softint; port->tqueue.data = port; + port->break_flag = 0; /* * Start up serial port @@ -871,6 +1044,23 @@ } #endif +#ifdef CONFIG_SH_KGDB_CONSOLE + if (kgdbcons.cflag && kgdbcons.index == line) { + tty->termios->c_cflag = kgdbcons.cflag; + port->gs.baud = kgdb_baud; + sercons.cflag = 0; + sci_set_real_termios(port); + } +#elif CONFIG_SH_KGDB + /* Even for non-console, may defer to kgdb */ + if (port == kgdb_sci_port && kgdb_in_gdb_mode) { + tty->termios->c_cflag = kgdb_cflag; + port->gs.baud = kgdb_baud; + sercons.cflag = 0; + sci_set_real_termios(port); + } +#endif /* CONFIG_SH_KGDB */ + sci_enable_rx_interrupts(port); port->gs.session = current->session; @@ -975,6 +1165,7 @@ * was throttled */ port->gs.flags &= ~SCI_RX_THROTTLE; + sci_enable_rx_interrupts(port); return; } @@ -1260,11 +1451,21 @@ break; } - co->cflag = cflag; - sercons_baud = baud; +#ifdef CONFIG_SH_KGDB + if (kgdb_in_gdb_mode && sercons_port == kgdb_sci_port) { + co->cflag = kgdb_cflag; + sercons_baud = kgdb_baud; + sercons_port->old_cflag = cflag; + } + else +#endif /* CONFIG_SH_KGDB */ + { + co->cflag = cflag; + sercons_baud = baud; - sci_set_termios_cflag(sercons_port, cflag, baud); - sercons_port->old_cflag = cflag; + sci_set_termios_cflag(sercons_port, cflag, baud); + sercons_port->old_cflag = cflag; + } return 0; } @@ -1298,3 +1499,110 @@ #endif } #endif /* CONFIG_SERIAL_CONSOLE */ + + +#ifdef CONFIG_SH_KGDB + +/* Initialise the KGDB serial port */ +int kgdb_sci_setup(void) +{ + int cflag = CREAD | HUPCL | CLOCAL; + + if ((kgdb_portnum < 0) || (kgdb_portnum >= SCI_NPORTS)) + return -1; + + kgdb_sci_port = &sci_ports[kgdb_portnum]; + + switch (kgdb_baud) { + case 115200: + cflag |= B115200; + break; + case 57600: + cflag |= B57600; + break; + case 38400: + cflag |= B38400; + break; + case 19200: + cflag |= B19200; + break; + case 9600: + default: + cflag |= B9600; + kgdb_baud = 9600; + break; + } + + switch (kgdb_bits) { + case '7': + cflag |= CS7; + break; + default: + case '8': + cflag |= CS8; + break; + } + + switch (kgdb_parity) { + case 'O': + cflag |= PARODD; + break; + case 'E': + cflag |= PARENB; + break; + } + + kgdb_cflag = cflag; + sci_set_termios_cflag(kgdb_sci_port, kgdb_cflag, kgdb_baud); + + /* Set up the interrupt for BREAK from GDB */ + /* Commented out for now since it may not be possible yet... + request_irq(kgdb_sci_port->irqs[0], kgdb_break_interrupt, + SA_INTERRUPT, "sci", kgdb_sci_port); + sci_enable_rx_interrupts(kgdb_sci_port); + */ + + /* Setup complete: initialize function pointers */ + kgdb_getchar = kgdb_sci_getchar; + kgdb_putchar = kgdb_sci_putchar; + + return 0; +} + +#ifdef CONFIG_SH_KGDB_CONSOLE + +/* Create a console device */ +static kdev_t kgdb_console_device(struct console *c) +{ + return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index); +} + +/* Set up the KGDB console */ +static int __init kgdb_console_setup(struct console *co, char *options) +{ + /* NB we ignore 'options' because we've already done the setup */ + co->cflag = kgdb_cflag; + + return 0; +} + +/* Register the KGDB console so we get messages (d'oh!) */ +void __init kgdb_console_init(void) +{ + register_console(&kgdbcons); +} + +/* The console structure for KGDB */ +static struct console kgdbcons = { + name:"ttySC", + write:kgdb_console_write, + device:kgdb_console_device, + wait_key:serial_console_wait_key, + setup:kgdb_console_setup, + flags:CON_PRINTBUFFER | CON_ENABLED, + index:-1, +}; + +#endif /* CONFIG_SH_KGDB_CONSOLE */ + +#endif /* CONFIG_SH_KGDB */