patch-2.4.23 linux-2.4.23/drivers/char/sh-sci.c
Next file: linux-2.4.23/drivers/char/sh-sci.h
Previous file: linux-2.4.23/drivers/char/serial.c
Back to the patch index
Back to the overall index
- Lines: 406
- Date:
2003-11-28 10:26:20.000000000 -0800
- Orig file:
linux-2.4.22/drivers/char/sh-sci.c
- Orig date:
2003-08-25 04:44:41.000000000 -0700
diff -urN linux-2.4.22/drivers/char/sh-sci.c linux-2.4.23/drivers/char/sh-sci.c
@@ -1,4 +1,4 @@
-/* $Id: sh-sci.c,v 1.1.1.1.2.7 2003/07/16 18:45:31 yoshii Exp $
+/* $Id: sh-sci.c,v 1.1.1.1.2.10 2003/09/17 23:38:56 davidm-sf 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 SecureEdge. David McCullough (2002)
* Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
*
* TTY code is based on sx.c (Specialix SX driver) by:
@@ -239,6 +240,51 @@
#endif /* CONFIG_SERIAL_CONSOLE */
+#if defined(CONFIG_SH_SECUREEDGE5410)
+
+struct timer_list sci_timer_struct;
+static unsigned char sci_dcdstatus[2];
+
+/*
+ * This subroutine is called when the RS_TIMER goes off. It is used
+ * to monitor the state of the DCD lines - since they have no edge
+ * sensors and interrupt generators.
+ */
+static void sci_timer(unsigned long data)
+{
+ unsigned short s, i;
+ unsigned char dcdstatus[2];
+
+ s = SECUREEDGE_READ_IOPORT();
+ dcdstatus[0] = !(s & 0x10);
+ dcdstatus[1] = !(s & 0x1);
+
+ for (i = 0; i < 2; i++) {
+ if (dcdstatus[i] != sci_dcdstatus[i]) {
+ if (sci_ports[i].gs.count != 0) {
+ if (sci_ports[i].gs.flags & ASYNC_CHECK_CD) {
+ if (dcdstatus[i]) { /* DCD has gone high */
+ wake_up_interruptible(&sci_ports[i].gs.open_wait);
+ } else if (!((sci_ports[i].gs.flags&ASYNC_CALLOUT_ACTIVE) &&
+ (sci_ports[i].gs.flags & ASYNC_CALLOUT_NOHUP))) {
+ if (sci_ports[i].gs.tty)
+ tty_hangup(sci_ports[i].gs.tty);
+ }
+ }
+ }
+ }
+ sci_dcdstatus[i] = dcdstatus[i];
+ }
+
+ sci_timer_struct.expires = jiffies + HZ/25;
+ add_timer(&sci_timer_struct);
+}
+
+#endif
+
+
+
+
#ifdef CONFIG_SH_KGDB
/* Is the SCI ready, ie is there a char waiting? */
@@ -359,7 +405,7 @@
/* We need to set SCPCR to enable RTS/CTS */
data = ctrl_inw(SCPCR);
/* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
- ctrl_outw(data&0x0fcf, SCPCR);
+ ctrl_outw(data&0x0cff, SCPCR);
}
if (cflag & CRTSCTS)
fcr_val |= SCFCR_MCE;
@@ -370,7 +416,7 @@
data = ctrl_inw(SCPCR);
/* Clear out SCP7MD1,0, SCP4MD1,0,
Set SCP6MD1,0 = {01} (output) */
- ctrl_outw((data&0x0fcf)|0x1000, SCPCR);
+ ctrl_outw((data&0x0cff)|0x1000, SCPCR);
data = ctrl_inb(SCPDR);
/* Set /RTS2 (bit6) = 0 */
@@ -413,7 +459,29 @@
/* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
/* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
/* If you have signals for DTR and DCD, please implement here. */
- ;
+
+#if defined(CONFIG_SH_SECUREEDGE5410)
+ int flags;
+
+ save_and_cli(flags);
+ if (port == &sci_ports[1]) { /* port 1 only */
+ if (dtr == 0)
+ SECUREEDGE_WRITE_IOPORT(0x0080, 0x0080);
+ else if (dtr == 1)
+ SECUREEDGE_WRITE_IOPORT(0x0000, 0x0080);
+ }
+ if (port == &sci_ports[0]) { /* port 0 only */
+ if (dtr == 0)
+ SECUREEDGE_WRITE_IOPORT(0x0200, 0x0200);
+ else if (dtr == 1)
+ SECUREEDGE_WRITE_IOPORT(0x0000, 0x0200);
+ if (rts == 0)
+ SECUREEDGE_WRITE_IOPORT(0x0100, 0x0100);
+ else if (rts == 1)
+ SECUREEDGE_WRITE_IOPORT(0x0000, 0x0100);
+ }
+ restore_flags(flags);
+#endif
}
static int sci_getsignals(struct sci_port *port)
@@ -421,15 +489,34 @@
/* This routine is used for geting signals of: DTR, DCD, DSR, RI,
and CTS/RTS */
+#if defined(CONFIG_SH_SECUREEDGE5410)
+ if (port == &sci_ports[1]) { /* port 1 only */
+ unsigned short s = SECUREEDGE_READ_IOPORT();
+ int rc = TIOCM_RTS|TIOCM_DSR|TIOCM_CTS;
+
+ if ((s & 0x0001) == 0)
+ rc |= TIOCM_CAR;
+ if ((SECUREEDGE_READ_IOPORT() & 0x0080) == 0)
+ rc |= TIOCM_DTR;
+ return(rc);
+ }
+ if (port == &sci_ports[0]) { /* port 0 only */
+ unsigned short s = SECUREEDGE_READ_IOPORT();
+ int rc = TIOCM_DSR;
+
+ if ((s & 0x0010) == 0)
+ rc |= TIOCM_CAR;
+ if ((s & 0x0004) == 0)
+ rc |= TIOCM_CTS;
+ if ((SECUREEDGE_READ_IOPORT() & 0x0200) == 0)
+ rc |= TIOCM_DTR;
+ if ((SECUREEDGE_READ_IOPORT() & 0x0100) == 0)
+ rc |= TIOCM_RTS;
+ return(rc);
+ }
+#endif
+
return TIOCM_DTR|TIOCM_RTS|TIOCM_DSR;
-/*
- (((o_stat & OP_DTR)?TIOCM_DTR:0) |
- ((o_stat & OP_RTS)?TIOCM_RTS:0) |
- ((i_stat & IP_CTS)?TIOCM_CTS:0) |
- ((i_stat & IP_DCD)?TIOCM_CAR:0) |
- ((i_stat & IP_DSR)?TIOCM_DSR:0) |
- ((i_stat & IP_RI) ?TIOCM_RNG:0)
-*/
}
static void sci_set_baud(struct sci_port *port, int baud)
@@ -458,6 +545,11 @@
case 57600:
t = BPS_57600;
break;
+ case 230400:
+ if (BPS_230400 != BPS_115200) {
+ t = BPS_230400;
+ break;
+ }
default:
printk(KERN_INFO "sci: unsupported baud rate: %d, using 115200 instead.\n", baud);
case 115200:
@@ -513,6 +605,11 @@
port->init_pins(port, cflag);
sci_out(port, SCSCR, SCSCR_INIT(port));
+
+ if (cflag & CLOCAL)
+ port->gs.flags &= ~ASYNC_CHECK_CD;
+ else
+ port->gs.flags |= ASYNC_CHECK_CD;
}
static int sci_set_real_termios(void *ptr)
@@ -525,22 +622,6 @@
sci_enable_rx_interrupts(port);
}
- /* Tell line discipline whether we will do input cooking */
- if (I_OTHER(port->gs.tty))
- clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
- else
- set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
-
-/* Tell line discipline whether we will do output cooking.
- * If OPOST is set and no other output flags are set then we can do output
- * processing. Even if only *one* other flag in the O_OTHER group is set
- * we do cooking in software.
- */
- if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty))
- set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
- else
- clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
-
return 0;
}
@@ -561,8 +642,8 @@
static void sci_transmit_chars(struct sci_port *port)
{
- int count, i;
- int txroom;
+ unsigned int count, i;
+ unsigned int txroom;
unsigned long flags;
unsigned short status;
unsigned short ctrl;
@@ -645,7 +726,7 @@
static inline void sci_receive_chars(struct sci_port *port,
struct pt_regs *regs)
{
- int i, count;
+ int count;
struct tty_struct *tty;
int copied=0;
unsigned short status;
@@ -655,6 +736,7 @@
return;
tty = port->gs.tty;
+
while (1) {
if (port->type == PORT_SCIF) {
#if defined(CONFIG_CPU_SUBTYPE_SH7300)
@@ -666,34 +748,41 @@
count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
}
- /* Don't copy more bytes than there is room for in the buffer */
- if (tty->flip.count + count > TTY_FLIPBUF_SIZE)
- count = TTY_FLIPBUF_SIZE - tty->flip.count;
+ /* we must clear RDF or we get stuck in the interrupt for ever */
+ sci_in(port, SCxSR); /* dummy read */
+ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
/* If for any reason we can't copy more data, we're done! */
if (count == 0)
break;
if (port->type == PORT_SCI) {
- tty->flip.char_buf_ptr[0] = sci_in(port, SCxRDR);
- tty->flip.flag_buf_ptr[0] = TTY_NORMAL;
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ *tty->flip.char_buf_ptr++ = sci_in(port, SCxRDR);
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ tty->flip.count++;
+ port->icount.rx++;
+ copied++;
+ count--;
+ }
} else {
- for (i=0; i<count; i++) {
+ while (count > 0 && tty->flip.count < TTY_FLIPBUF_SIZE){
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--;
+ count--;
continue;
}
/* Nonzero => end-of-break */
dprintk("scif: debounce<%02x>\n", c);
port->break_flag = 0;
if (STEPFN(c)) {
- count--; i--;
+ count--;
continue;
}
}
@@ -706,7 +795,7 @@
handle_sysrq(c, regs,
NULL, NULL);
break_pressed = 0;
- count--; i--;
+ count--;
continue;
} else if (c != 0) {
break_pressed = 0;
@@ -715,29 +804,31 @@
#endif /* CONFIG_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */
/* Store data and status */
- tty->flip.char_buf_ptr[i] = c;
+ *tty->flip.char_buf_ptr++ = c;
+
if (status&SCxSR_FER(port)) {
- tty->flip.flag_buf_ptr[i] = TTY_FRAME;
+ *tty->flip.flag_buf_ptr++ = TTY_FRAME;
dprintk("sci: frame error\n");
} else if (status&SCxSR_PER(port)) {
- tty->flip.flag_buf_ptr[i] = TTY_PARITY;
+ *tty->flip.flag_buf_ptr++ = TTY_PARITY;
dprintk("sci: parity error\n");
} else {
- tty->flip.flag_buf_ptr[i] = TTY_NORMAL;
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
}
+ tty->flip.count++;
+ port->icount.rx++;
+ copied++;
+ count--;
}
}
- sci_in(port, SCxSR); /* dummy read */
- sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-
- /* Update the kernel buffer end */
- tty->flip.count += count;
- tty->flip.char_buf_ptr += count;
- tty->flip.flag_buf_ptr += count;
-
- copied += count;
- port->icount.rx += count;
+ /* drop any remaining chars, we are full */
+ if (count > 0) {
+ /* force an overrun error on last received char */
+ tty->flip.flag_buf_ptr[TTY_FLIPBUF_SIZE - 1] = TTY_OVERRUN;
+ while (count-- > 0)
+ (void) sci_in(port, SCxRDR);
+ }
}
if (copied)
@@ -821,9 +912,11 @@
*tty->flip.flag_buf_ptr++ = TTY_BREAK;
dprintk("sci: BREAK detected\n");
}
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
break_continue:
+#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40)
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined (CONFIG_CPU_SUBTYPE_SH7751) || 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);
@@ -994,6 +1087,15 @@
static int sci_get_CD(void * ptr)
{
/* If you have signal for CD (Carrier Detect), please change here. */
+
+#if defined(CONFIG_SH_SECUREEDGE5410)
+ struct sci_port *port = ptr;
+
+ if (port == &sci_ports[0] || port == &sci_ports[1])
+ if ((sci_getsignals(port) & TIOCM_CAR) == 0)
+ return 0;
+#endif
+
return 1;
}
@@ -1409,6 +1511,18 @@
(port->type == PORT_SCI) ? "SCI" : "SCIF");
}
+#if defined(CONFIG_SH_SECUREEDGE5410)
+ init_timer(&sci_timer_struct);
+ sci_timer_struct.function = sci_timer;
+ sci_timer_struct.data = 0;
+ sci_timer_struct.expires = jiffies + HZ/25;
+ add_timer(&sci_timer_struct);
+
+ j = SECUREEDGE_READ_IOPORT();
+ sci_dcdstatus[0] = !(j & 0x10);
+ sci_dcdstatus[1] = !(j & 0x1);
+#endif
+
sci_init_drivers();
#ifdef CONFIG_SH_STANDARD_BIOS
@@ -1425,6 +1539,9 @@
void cleanup_module(void)
{
+#if defined(CONFIG_SH_SECUREEDGE5410)
+ del_timer(&sci_timer_struct);
+#endif
tty_unregister_driver(&sci_driver);
tty_unregister_driver(&sci_callout_driver);
}
@@ -1495,6 +1612,9 @@
case 115200:
cflag |= B115200;
break;
+ case 230400:
+ cflag |= B230400;
+ break;
case 9600:
default:
cflag |= B9600;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)