patch-2.4.22 linux-2.4.22/drivers/char/sh-sci.c

Next file: linux-2.4.22/drivers/char/sh-sci.h
Previous file: linux-2.4.22/drivers/char/sgiserial.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/char/sh-sci.c linux-2.4.22/drivers/char/sh-sci.c
@@ -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.2.7 2003/07/16 18:45:31 yoshii Exp $
  *
  *  linux/drivers/char/sh-sci.c
  *
@@ -6,6 +6,7 @@
  *  Copyright (C) 1999, 2000  Niibe Yutaka
  *  Copyright (C) 2000  Sugioka Toshinobu
  *  Modified to support multiple serial ports. Stuart Menefy (May 2000).
+ *  Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
  *
  * TTY code is based on sx.c (Specialix SX driver) by:
  *
@@ -32,7 +33,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#ifdef CONFIG_SERIAL_CONSOLE
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SH_KGDB_CONSOLE)
 #include <linux/console.h>
 #endif
 
@@ -50,17 +51,39 @@
 
 #include "sh-sci.h"
 
+#ifdef CONFIG_SH_KGDB
+#include <asm/kgdb.h>
+
+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 <linux/sysrq.h>
+static int break_pressed;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#endif /* CONFIG_SERIAL_CONSOLE */
 
 /* Function prototypes */
+#if !defined(SCIF_ONLY)
 static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag);
+#endif
 #ifndef SCI_ONLY
 static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag);
-#if defined(__sh3__)
+#if defined(__sh3__) && !defined(CONFIG_CPU_SUBTYPE_SH7300)
 static void sci_init_pins_irda(struct sci_port* port, unsigned int cflag);
 #endif
 #endif
@@ -114,7 +137,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 +179,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 +191,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) {
 	    /*  $<packet info>#<checksum>. */
 	    do {
 		unsigned char c;
@@ -197,15 +229,101 @@
 		put_char(port, lowhex(checksum));
 	    } while  (get_char(port) != '+');
 	} else
-#endif
+#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
 	for (i=0; i<count; i++) {
 		if (*p == 10)
 			put_char(port, '\r');
 		put_char(port, *p++);
 	}
 }
-#endif
+#endif /* CONFIG_SERIAL_CONSOLE */
+
+
+#ifdef CONFIG_SH_KGDB
+
+/* Is the SCI ready, ie is there a char waiting? */
+static int kgdb_is_char_ready(struct sci_port *port)
+{
+        unsigned short status = sci_in(port, SCxSR);
+
+        if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port)))
+                kgdb_handle_error(port);
+
+        return (status & SCxSR_RDxF(port));
+}
+
+/* Write a char */
+static void kgdb_put_char(struct sci_port *port, char c)
+{
+        unsigned short status;
+
+        do
+                status = sci_in(port, SCxSR);
+        while (!(status & SCxSR_TDxE(port)));
+
+        sci_out(port, SCxTDR, c);
+        sci_in(port, SCxSR);    /* Dummy read */
+        sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+}
+
+/* Get a char if there is one, else ret -1 */
+static int kgdb_get_char(struct sci_port *port)
+{
+        int c;
 
+        if (kgdb_is_char_ready(port) == 0)
+                c = -1;
+        else {
+                c = sci_in(port, SCxRDR);
+                sci_in(port, SCxSR);    /* Dummy read */
+                sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+        }
+
+        return c;
+}
+
+/* Called from kgdbstub.c to get a character, i.e. is blocking */
+static int kgdb_sci_getchar(void)
+{
+        volatile int c;
+
+        /* Keep trying to read a character, this could be neater */
+        while ((c = kgdb_get_char(kgdb_sci_port)) < 0);
+
+        return c;
+}
+
+/* Called from kgdbstub.c to put a character, just a wrapper */
+static void kgdb_sci_putchar(int c)
+{
+
+        kgdb_put_char(kgdb_sci_port, c);
+}
+
+/* Clear any errors on the SCI */
+static void kgdb_handle_error(struct sci_port *port)
+{
+        sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));  /* Clear error flags */
+}
+
+/* Breakpoint if there's a break sent on the serial port */
+static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+        struct sci_port *port = ptr;
+        unsigned short status = sci_in(port, SCxSR);
+
+        if (status & SCxSR_BRK(port)) {
+
+                /* Break into the debugger if a break is detected */
+                BREAKPOINT();
+
+                /* Clear */
+                sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+                return;
+        }
+}
+
+#endif /* CONFIG_SH_KGDB */
 
 static struct real_driver sci_real_driver = {
 	sci_disable_tx_interrupts,
@@ -229,11 +347,12 @@
 
 #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
 #if defined(__sh3__)
-/* For SH7707, SH7709, SH7709A, SH7729 */
+/* For SH7300, SH7707, SH7709, SH7709A, SH7729 */
 static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag)
 {
 	unsigned int fcr_val = 0;
 
+#if !defined(CONFIG_CPU_SUBTYPE_SH7300) /* SH7300 doesn't use RTS/CTS */
 	{
 		unsigned short data;
 
@@ -257,6 +376,7 @@
 		/* Set /RTS2 (bit6) = 0 */
 		ctrl_outb(data&0xbf, SCPDR);
 	}
+#endif
 	sci_out(port, SCFCR, fcr_val);
 }
 
@@ -280,7 +400,7 @@
 	if (cflag & CRTSCTS) {
 		fcr_val |= SCFCR_MCE;
 	} else {
-		ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
+		sci_out(port, SCSPTR, 0x0080); /* Set RTS = 1 */
 	}
 	sci_out(port, SCFCR, fcr_val);
 }
@@ -372,7 +492,11 @@
 	sci_out(port, SCSCR, 0x00);	/* TE=0, RE=0, CKE1=0 */
 
 	if (port->type == PORT_SCIF) {
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+		sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST | SCFCR_TCRST);
+#else
 		sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+#endif
 	}
 
 	smr_val = sci_in(port, SCSMR) & 3;
@@ -381,7 +505,7 @@
 	if (cflag & PARENB)
 		smr_val |= 0x20;
 	if (cflag & PARODD)
-		smr_val |= 0x10;
+		smr_val |= 0x30;
 	if (cflag & CSTOPB)
 		smr_val |= 0x08;
 	sci_out(port, SCSMR, smr_val);
@@ -461,14 +585,18 @@
 	while (1) {
 		count = port->gs.xmit_cnt;
 		if (port->type == PORT_SCIF) {
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+			txroom = 64 - (sci_in(port, SCFDR)>>8);
+#else
 			txroom = 16 - (sci_in(port, SCFDR)>>8);
+#endif
 		} else {
 			txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
 		}
 		if (count > 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 +639,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;
@@ -525,7 +657,11 @@
 	tty = port->gs.tty;
 	while (1) {
 		if (port->type == PORT_SCIF) {
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+			count = sci_in(port, SCFDR)&0x007f;
+#else
 			count = sci_in(port, SCFDR)&0x001f;
+#endif
 		} else {
 			count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
 		}
@@ -534,7 +670,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 +679,43 @@
 			tty->flip.flag_buf_ptr[0] = TTY_NORMAL;
 		} else {
 			for (i=0; i<count; i++) {
-				tty->flip.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");
@@ -572,6 +743,10 @@
 	if (copied)
 		/* Tell the rest of the system the news. New characters! */
 		tty_flip_buffer_push(tty);
+	else {
+		sci_in(port, SCxSR); /* dummy read */
+		sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+	}
 }
 
 static inline int sci_handle_errors(struct sci_port *port)
@@ -624,13 +799,31 @@
 	struct tty_struct *tty = port->gs.tty;
 
 	if (status&SCxSR_BRK(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
+#if defined(__SH3__)
+		/* Debounce break */
+		if (port->break_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)
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40)
 	/* XXX: Handle SCIF overrun error */
 	if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
 		sci_out(port, SCLSR, 0);
@@ -656,7 +849,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);
@@ -703,6 +896,28 @@
 	sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
 }
 
+static void sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+        unsigned short ssr_status, scr_status;
+        struct sci_port *port = ptr;
+
+        ssr_status=sci_in(port,SCxSR);
+        scr_status=sci_in(port,SCSCR);
+
+        if((ssr_status&0x0020) && (scr_status&0x0080)){ /* Tx Interrupt */
+                sci_tx_interrupt(irq, ptr, regs);
+        }
+        if((ssr_status&0x0002) && (scr_status&0x0040)){ /* Rx Interrupt */
+                sci_rx_interrupt(irq, ptr, regs);
+        }
+        if((ssr_status&0x0080) && (scr_status&0x0400)){ /* Error Interrupt */
+                sci_er_interrupt(irq, ptr, regs);
+        }
+        if((ssr_status&0x0010) && (scr_status&0x0200)){ /* Break Interrupt */
+                sci_br_interrupt(irq, ptr, regs);
+        }
+}
+
 static void do_softint(void *private_)
 {
 	struct sci_port *port = (struct sci_port *) private_;
@@ -811,7 +1026,7 @@
 static int sci_open(struct tty_struct * tty, struct file * filp)
 {
 	struct sci_port *port;
-	int retval, line;
+	int retval = 0, line;
 
 	line = MINOR(tty->device) - SCI_MINOR_START;
 
@@ -820,6 +1035,14 @@
 
 	port = &sci_ports[line];
 
+#if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
+	if (port->base == 0) {
+		port->base = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
+		if (!port->base)
+			goto failed_1;
+	}
+#endif
+
 	tty->driver_data = port;
 	port->gs.tty = tty;
 	port->gs.count++;
@@ -827,31 +1050,32 @@
 	port->event = 0;
 	port->tqueue.routine = do_softint;
 	port->tqueue.data = port;
+	port->break_flag = 0;
+
+	if (port->gs.count == 1) {
+		MOD_INC_USE_COUNT;
+
+		retval = sci_request_irq(port);
+		if (retval) {
+			goto failed_1;
+		}
+	}
 
 	/*
 	 * Start up serial port
 	 */
 	retval = gs_init_port(&port->gs);
 	if (retval) {
-		goto failed_1;
+		goto failed_2;
 	}
 
 	port->gs.flags |= GS_ACTIVE;
 	sci_setsignals(port, 1,1);
 
-	if (port->gs.count == 1) {
-		MOD_INC_USE_COUNT;
-
-		retval = sci_request_irq(port);
-		if (retval) {
-			goto failed_2;
-		}
-	}
-
 	retval = gs_block_til_ready(port, filp);
 
 	if (retval) {
-		goto failed_3;
+		goto failed_2;
 	}
 
 	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
@@ -871,6 +1095,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;
@@ -878,11 +1119,10 @@
 
 	return 0;
 
-failed_3:
-	sci_free_irq(port);
 failed_2:
-	MOD_DEC_USE_COUNT;
+	sci_free_irq(port);
 failed_1:
+	MOD_DEC_USE_COUNT;
 	port->gs.count--;
 	return retval;
 }
@@ -975,6 +1215,7 @@
 	 * was throttled
 	 */
 	port->gs.flags &= ~SCI_RX_THROTTLE;
+	sci_enable_rx_interrupts(port);
 	return;
 }
 
@@ -1110,14 +1351,27 @@
 		sci_br_interrupt,
 	};
 
-	for (i=0; i<4; i++) {
-		if (!port->irqs[i]) continue;
-		if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
+	if(port->irqs[0] == port->irqs[1]){
+		if (!port->irqs[0]){
+			printk(KERN_ERR "sci: Cannot allocate irq.(IRQ=0)\n");
+			return -ENODEV;
+		}
+		if (request_irq(port->irqs[0], sci_mpxed_interrupt, SA_INTERRUPT,
 				"sci", port)) {
 			printk(KERN_ERR "sci: Cannot allocate irq.\n");
 			return -ENODEV;
 		}
 	}
+	else{
+		for (i=0; i<4; i++) {
+			if (!port->irqs[i]) continue;
+			if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
+				"sci", port)) {
+				printk(KERN_ERR "sci: Cannot allocate irq.\n");
+				return -ENODEV;
+			}
+		}
+	}
 	return 0;
 }
 
@@ -1125,10 +1379,18 @@
 {
 	int i;
 
-	for (i=0; i<4; i++) {
-		if (!port->irqs[i]) continue;
-		free_irq(port->irqs[i], port);
-	}
+        if(port->irqs[0] == port->irqs[1]){
+                if(!port->irqs[0]){
+                        printk("sci: sci_free_irq error\n");
+                }else{
+                        free_irq(port->irqs[0], port);
+                }
+        }else{
+                for (i=0; i<4; i++) {
+                        if (!port->irqs[i]) continue;
+                        free_irq(port->irqs[i], port);
+                }
+        }
 }
 
 static char banner[] __initdata =
@@ -1202,6 +1464,12 @@
 
 	sercons_port = &sci_ports[co->index];
 
+#if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
+	sercons_port->base = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
+	if (!sercons_port->base)
+		return -EINVAL;
+#endif
+
 	if (options) {
 		baud = simple_strtoul(options, NULL, 10);
 		s = options;
@@ -1251,11 +1519,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;
 }
@@ -1288,3 +1566,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 */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)