2008-08-06 21:24:54

by Aristeu Rozanski

[permalink] [raw]
Subject: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

This patch adds support for DTR/DSR hardware flow control on 8250 driver on x86
machines. It's done by adding a CDTRDSR flag to work just like CRTSCTS, which is
not done on other architectures on purpose (so each maintainer can allocate it).

This patch was tested with success with a serial printer configured with a small
buffer and DTR/DSR flow control.

This is based on the work of Michael Westermann (http://lkml.org/lkml/2007/8/31/133)

Comments more than welcome.

Signed-off-by: Aristeu Rozanski <[email protected]>

---
drivers/serial/8250.c | 12 ++++++++--
drivers/serial/serial_core.c | 42 ++++++++++++++++++++++++++++++++++-
include/asm-x86/termbits.h | 1
include/linux/serial_core.h | 51 +++++++++++++++++++++++++++----------------
include/linux/termios.h | 5 ++++
5 files changed, 90 insertions(+), 21 deletions(-)

--- linus-2.6.orig/drivers/serial/8250.c 2008-08-05 16:44:26.000000000 -0400
+++ linus-2.6/drivers/serial/8250.c 2008-08-05 18:45:01.000000000 -0400
@@ -1409,7 +1409,7 @@ static unsigned int check_modem_status(s
if (status & UART_MSR_TERI)
up->port.icount.rng++;
if (status & UART_MSR_DDSR)
- up->port.icount.dsr++;
+ uart_handle_dsr_change(&up->port, status & UART_MSR_DSR);
if (status & UART_MSR_DDCD)
uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
if (status & UART_MSR_DCTS)
@@ -1739,9 +1739,17 @@ static inline void wait_for_xmitr(struct
unsigned int tmout;
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
+ struct uart_info *info = up->port.info;
+
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
- if (msr & UART_MSR_CTS)
+
+ if ((info->flags & UIF_CTS_FLOW) &&
+ (msr & UART_MSR_CTS))
break;
+ else if ((info->flags & UIF_DSR_FLOW) &&
+ (msr & UART_MSR_DSR))
+ break;
+
udelay(1);
touch_nmi_watchdog();
}
--- linus-2.6.orig/drivers/serial/serial_core.c 2008-08-05 16:44:26.000000000 -0400
+++ linus-2.6/drivers/serial/serial_core.c 2008-08-05 18:45:01.000000000 -0400
@@ -194,6 +194,13 @@ static int uart_startup(struct uart_stat
spin_unlock_irq(&port->lock);
}

+ if (info->flags & UIF_DSR_FLOW) {
+ spin_lock_irq(&port->lock);
+ if (!(port->ops->get_mctrl(port) & TIOCM_DSR))
+ info->port.tty->hw_stopped = 1;
+ spin_unlock_irq(&port->lock);
+ }
+
info->flags |= UIF_INITIALIZED;

clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
@@ -448,6 +455,11 @@ uart_change_speed(struct uart_state *sta
else
state->info->flags &= ~UIF_CTS_FLOW;

+ if (termios->c_cflag & CDTRDSR)
+ state->info->flags |= UIF_DSR_FLOW;
+ else
+ state->info->flags &= ~UIF_DSR_FLOW;
+
if (termios->c_cflag & CLOCAL)
state->info->flags &= ~UIF_CHECK_CD;
else
@@ -611,6 +623,8 @@ static void uart_throttle(struct tty_str

if (tty->termios->c_cflag & CRTSCTS)
uart_clear_mctrl(state->port, TIOCM_RTS);
+ if (tty->termios->c_cflag & CDTRDSR)
+ uart_clear_mctrl(state->port, TIOCM_DTR);
}

static void uart_unthrottle(struct tty_struct *tty)
@@ -627,6 +641,8 @@ static void uart_unthrottle(struct tty_s

if (tty->termios->c_cflag & CRTSCTS)
uart_set_mctrl(port, TIOCM_RTS);
+ if (tty->termios->c_cflag & CDTRDSR)
+ uart_set_mctrl(port, TIOCM_DTR);
}

static int uart_get_info(struct uart_state *state,
@@ -1212,6 +1228,9 @@ static void uart_set_termios(struct tty_
if (!(cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags))
mask |= TIOCM_RTS;
+ if (!(cflag & CDTRDSR) ||
+ !test_bit(TTY_THROTTLED, &tty->flags))
+ mask &= ~TIOCM_DTR;
uart_set_mctrl(state->port, mask);
}

@@ -1232,6 +1251,24 @@ static void uart_set_termios(struct tty_
}
spin_unlock_irqrestore(&state->port->lock, flags);
}
+
+ /* Handle turning off CDTRDSR */
+ if ((old_termios->c_cflag & CDTRDSR) && !(cflag & CDTRDSR)) {
+ spin_lock_irqsave(&state->port->lock, flags);
+ tty->hw_stopped = 0;
+ __uart_start(tty);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ }
+
+ if (!(old_termios->c_cflag & CDTRDSR) && (cflag & CDTRDSR)) {
+ spin_lock_irqsave(&state->port->lock, flags);
+ if (!(state->port->ops->get_mctrl(state->port) & TIOCM_DSR)) {
+ tty->hw_stopped = 1;
+ state->port->ops->stop_tx(state->port);
+ }
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ }
+
#if 0
/*
* No need to wake up processes in open wait, since they
@@ -1511,7 +1548,8 @@ uart_block_til_ready(struct file *filp,
* not set RTS here - we want to make sure we catch
* the data from the modem.
*/
- if (info->port.tty->termios->c_cflag & CBAUD)
+ if (info->port.tty->termios->c_cflag & CBAUD &&
+ !(info->port.tty->termios->c_cflag & CDTRDSR))
uart_set_mctrl(port, TIOCM_DTR);

/*
@@ -1959,6 +1997,8 @@ uart_set_options(struct uart_port *port,

if (flow == 'r')
termios.c_cflag |= CRTSCTS;
+ if (flow == 'd')
+ termios.c_cflag |= CDTRDSR;

/*
* some uarts on other side don't support no flow control.
--- linus-2.6.orig/include/asm-x86/termbits.h 2008-08-05 16:44:26.000000000 -0400
+++ linus-2.6/include/asm-x86/termbits.h 2008-08-06 13:33:57.000000000 -0400
@@ -157,6 +157,7 @@ struct ktermios {
#define B3500000 0010016
#define B4000000 0010017
#define CIBAUD 002003600000 /* input baud rate */
+#define CDTRDSR 004000000000 /* DTR/DSR flow control */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */

--- linus-2.6.orig/include/linux/serial_core.h 2008-08-05 16:44:26.000000000 -0400
+++ linus-2.6/include/linux/serial_core.h 2008-08-05 18:45:01.000000000 -0400
@@ -351,6 +351,7 @@ struct uart_info {
*
* FIXME: use the ASY_ definitions
*/
+#define UIF_DSR_FLOW ((__force uif_t) (1 << 24))
#define UIF_CHECK_CD ((__force uif_t) (1 << 25))
#define UIF_CTS_FLOW ((__force uif_t) (1 << 26))
#define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29))
@@ -505,34 +506,48 @@ uart_handle_dcd_change(struct uart_port
}

/**
- * uart_handle_cts_change - handle a change of clear-to-send state
+ * uart_handle_flow_control_change - handle a change of CTS or DSR
* @port: uart_port structure for the open port
- * @status: new clear to send status, nonzero if active
+ * @status: new CTS/DTR status, nonzero if active
*/
static inline void
-uart_handle_cts_change(struct uart_port *port, unsigned int status)
+uart_handle_flow_control_change(struct uart_port *port, unsigned int status)
{
struct uart_info *info = port->info;
struct tty_struct *tty = info->port.tty;

- port->icount.cts++;
-
- if (info->flags & UIF_CTS_FLOW) {
- if (tty->hw_stopped) {
- if (status) {
- tty->hw_stopped = 0;
- port->ops->start_tx(port);
- uart_write_wakeup(port);
- }
- } else {
- if (!status) {
- tty->hw_stopped = 1;
- port->ops->stop_tx(port);
- }
+ if (tty->hw_stopped) {
+ if (status) {
+ tty->hw_stopped = 0;
+ port->ops->start_tx(port);
+ uart_write_wakeup(port);
+ }
+ } else {
+ if (!status) {
+ tty->hw_stopped = 1;
+ port->ops->stop_tx(port);
}
}
}

+static inline void
+uart_handle_cts_change(struct uart_port *port, unsigned int status)
+{
+ struct uart_info *info = port->info;
+ port->icount.cts++;
+ if (info->flags & UIF_CTS_FLOW)
+ uart_handle_flow_control_change(port, status);
+}
+
+static inline void
+uart_handle_dsr_change(struct uart_port *port, unsigned int status)
+{
+ struct uart_info *info = port->info;
+ port->icount.dsr++;
+ if (info->flags & UIF_DSR_FLOW)
+ uart_handle_flow_control_change(port, status);
+}
+
#include <linux/tty_flip.h>

static inline void
@@ -556,7 +571,7 @@ uart_insert_char(struct uart_port *port,
* UART_ENABLE_MS - determine if port should enable modem status irqs
*/
#define UART_ENABLE_MS(port,cflag) ((port)->flags & UPF_HARDPPS_CD || \
- (cflag) & CRTSCTS || \
+ (cflag) & (CRTSCTS | CDTRDSR) || \
!((cflag) & CLOCAL))

#endif
--- linus-2.6.orig/include/linux/termios.h 2008-08-05 16:44:26.000000000 -0400
+++ linus-2.6/include/linux/termios.h 2008-08-05 18:45:01.000000000 -0400
@@ -4,4 +4,9 @@
#include <linux/types.h>
#include <asm/termios.h>

+#ifndef CDTRDSR
+#warning This architecture should implement CDTRDSR
+#define CDTRDSR 0 /* remove this when all architectures have a definition */
+#endif
+
#endif


2008-08-07 08:32:38

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

Hi,

On Wednesday 06 August 2008, Aristeu Rozanski wrote:
> This patch adds support for DTR/DSR hardware flow control on 8250 driver on
> x86 machines. It's done by adding a CDTRDSR flag to work just like CRTSCTS,
> which is not done on other architectures on purpose (so each maintainer can
> allocate it).

It's funny, serial flow control hasn't been discussed for a long time, and you're the third person to start a flow control related thread on this mailing list in a few days.

> This patch was tested with success with a serial printer configured with a
> small buffer and DTR/DSR flow control.
>
> This is based on the work of Michael Westermann
> (http://lkml.org/lkml/2007/8/31/133)
>
> Comments more than welcome.

Please read the '[PATCH/RFC] 8250: Auto RS485 direction control' thread for background information. In a nutshell we need more than just CTS/RTS and DTR/DSR, and we don't have enough c_cflags bits. We will probably have to create a new ioctl.

Best regards,

--
Laurent Pinchart
CSE Semaphore Belgium

Chaussee de Bruxelles, 732A
B-1410 Waterloo
Belgium

T +32 (2) 387 42 59
F +32 (2) 387 42 75


Attachments:
(No filename) (1.10 kB)
signature.asc (197.00 B)
This is a digitally signed message part.
Download all attachments

2008-08-07 12:28:06

by Alan

[permalink] [raw]
Subject: Re: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

> Please read the '[PATCH/RFC] 8250: Auto RS485 direction control' thread for background information. In a nutshell we need more than just CTS/RTS and DTR/DSR, and we don't have enough c_cflags bits. We will probably have to create a new ioctl.

Maybe - fortunately the kernel and user termios structure are now
independent so we can extend ktermios easily enough.

2008-08-11 19:28:42

by Jean-Pierre TOSONI

[permalink] [raw]
Subject: RE: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

In my opinion, DSR/DTR is another (wrong) way to do RTS/CTS flow control, so
I would have it implemented in setserial as a modifier to the CRTSCTS flag.

About a RS485 ioctl: could you consider the attached files which are already
in the Linux kernel (in include/asm-cris).
They define a TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h)
with allows to specify timings. Sounds just like what we want ?

JP Tosoni

> -----Original Message-----
> From: [email protected]
> [mailto:[email protected]]On Behalf Of
> Laurent Pinchart
> Sent: Thursday, August 07, 2008 10:32 AM
> To: Aristeu Rozanski
> Cc: [email protected]; [email protected]
> Subject: Re: [PATCH v1] 8250: add support for DTR/DSR hardware flow
> control
>
>
> Hi,
>
> On Wednesday 06 August 2008, Aristeu Rozanski wrote:
> > This patch adds support for DTR/DSR hardware flow control
> on 8250 driver on
> > x86 machines. It's done by adding a CDTRDSR flag to work
> just like CRTSCTS,
> > which is not done on other architectures on purpose (so
> each maintainer can
> > allocate it).
>
> It's funny, serial flow control hasn't been discussed for a
> long time, and you're the third person to start a flow
> control related thread on this mailing list in a few days.
>
> > This patch was tested with success with a serial printer
> configured with a
> > small buffer and DTR/DSR flow control.
> >
> > This is based on the work of Michael Westermann
> > (http://lkml.org/lkml/2007/8/31/133)
> >
> > Comments more than welcome.
>
> Please read the '[PATCH/RFC] 8250: Auto RS485 direction
> control' thread for background information. In a nutshell we
> need more than just CTS/RTS and DTR/DSR, and we don't have
> enough c_cflags bits. We will probably have to create a new ioctl.
>
> Best regards,
>
> --
> Laurent Pinchart
> CSE Semaphore Belgium
>
> Chaussee de Bruxelles, 732A
> B-1410 Waterloo
> Belgium
>
> T +32 (2) 387 42 59
> F +32 (2) 387 42 75
>


Attachments:
ioctls.h (2.80 kB)
rs485.h (454.00 B)
Download all attachments

2008-08-13 11:56:54

by Alan

[permalink] [raw]
Subject: Re: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

> About a RS485 ioctl: could you consider the attached files which are already
> in the Linux kernel (in include/asm-cris).
> They define a TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h)
> with allows to specify timings. Sounds just like what we want ?

That would make sense for hardware assisted RS485 but we still have to
sort out DTR/DSR as well

2008-08-18 15:43:33

by Alan

[permalink] [raw]
Subject: Re: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

On Thu, 7 Aug 2008 14:54:05 +0200
"Tosoni" <[email protected]> wrote:

> About a RS485 ioctl: could you consider the attached files which are already
> in the Linux kernel (in include/asm-cris).
> They define a TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h)
> with allows to specify timings. Sounds just like what we want ?

I had a deeper look at this for RS485 and the answer is "sort of". I've
reworked the structure to keep it the same size irrespective of 32/64bit
systems, and to make stuff flags that can be, plus add some extra u32
words in case we need to (.. when we need to ;)) add stuff later.

Comments, thoughts - will this do what people in the RS485 world need ?

Alan
--------------

tty: Cris has a nice RS485 ioctl so we should steal it

From: Alan Cox <[email protected]>

JP Tosoni observed:

"About a RS485 ioctl: could you consider the attached files which are
already in the Linux kernel (in include/asm-cris). They define a
TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h)
with allows to specify timings. Sounds just like what we want ?"

and he's right: sort of. Rework the structure to use flag bits and make the
time delay a fixed sized field so we don't get 32/64bit problems. Add the ioctls
to x86 so that people know what to add to their platform of choice.

Signed-off-by: Alan Cox <[email protected]>
---

include/asm-x86/ioctls.h | 2 ++
include/linux/serial.h | 16 ++++++++++++++++
2 files changed, 18 insertions(+), 0 deletions(-)


diff --git a/include/asm-x86/ioctls.h b/include/asm-x86/ioctls.h
index c0c338b..2cd4775 100644
--- a/include/asm-x86/ioctls.h
+++ b/include/asm-x86/ioctls.h
@@ -51,6 +51,8 @@
#define TCSETS2 _IOW('T', 0x2B, struct termios2)
#define TCSETSW2 _IOW('T', 0x2C, struct termios2)
#define TCSETSF2 _IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485 0x542E
+#define TIOCSRS485 0x542F
#define TIOCGPTN _IOR('T', 0x30, unsigned int)
/* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */
diff --git a/include/linux/serial.h b/include/linux/serial.h
index deb7143..1ea8d92 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -173,6 +173,22 @@ struct serial_icounter_struct {
int reserved[9];
};

+/*
+ * Serial interface for controlling RS485 settings on chips with suitable
+ * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
+ * platform. The set function returns the new state, with any unsupported bits
+ * reverted appropriately.
+ */
+
+struct serial_rs485 {
+ __u32 flags; /* RS485 feature flags */
+#define SER_RS485_ENABLED (1 << 0)
+#define SER_RS485_RTS_ON_SEND (1 << 1)
+#define SER_RS485_RTS_AFTER_SEND (1 << 2)
+ __u32 delay_rts_before_send; /* Milliseconds */
+ __u32 padding[6]; /* Memory is cheap, new structs
+ are a royal PITA .. */
+};

#ifdef __KERNEL__
#include <linux/compiler.h>

2008-08-20 22:14:22

by Aristeu Rozanski

[permalink] [raw]
Subject: Re: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

> > About a RS485 ioctl: could you consider the attached files which are already
> > in the Linux kernel (in include/asm-cris).
> > They define a TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h)
> > with allows to specify timings. Sounds just like what we want ?
>
> I had a deeper look at this for RS485 and the answer is "sort of". I've
> reworked the structure to keep it the same size irrespective of 32/64bit
> systems, and to make stuff flags that can be, plus add some extra u32
> words in case we need to (.. when we need to ;)) add stuff later.
>
> Comments, thoughts - will this do what people in the RS485 world need ?
as for DTR/DSR patch, will be used the same approach?

--
Aristeu

2008-08-21 10:41:12

by Alan

[permalink] [raw]
Subject: Re: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

On Wed, 20 Aug 2008 17:43:36 -0400
Aristeu Rozanski <[email protected]> wrote:

> > > About a RS485 ioctl: could you consider the attached files which are already
> > > in the Linux kernel (in include/asm-cris).
> > > They define a TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h)
> > > with allows to specify timings. Sounds just like what we want ?
> >
> > I had a deeper look at this for RS485 and the answer is "sort of". I've
> > reworked the structure to keep it the same size irrespective of 32/64bit
> > systems, and to make stuff flags that can be, plus add some extra u32
> > words in case we need to (.. when we need to ;)) add stuff later.
> >
> > Comments, thoughts - will this do what people in the RS485 world need ?
> as for DTR/DSR patch, will be used the same approach?

I'm still trying to get a sensible answer on how other Unixes handle it

2008-08-21 18:59:53

by Aristeu Rozanski

[permalink] [raw]
Subject: Re: [PATCH v1] 8250: add support for DTR/DSR hardware flow control

> > > > About a RS485 ioctl: could you consider the attached files which are already
> > > > in the Linux kernel (in include/asm-cris).
> > > > They define a TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h)
> > > > with allows to specify timings. Sounds just like what we want ?
> > >
> > > I had a deeper look at this for RS485 and the answer is "sort of". I've
> > > reworked the structure to keep it the same size irrespective of 32/64bit
> > > systems, and to make stuff flags that can be, plus add some extra u32
> > > words in case we need to (.. when we need to ;)) add stuff later.
> > >
> > > Comments, thoughts - will this do what people in the RS485 world need ?
> > as for DTR/DSR patch, will be used the same approach?
>
> I'm still trying to get a sensible answer on how other Unixes handle it
I did some research on that:
Solaris and AIX:
TC{G,S}ETX for extended options and only input flow control (DTRXOFF)
SCO:
{S,G}ETFLOW for configuring flow control, TXHARD, RXHARD for DTRDSR
FreeBSD:
cflags has 'dtrflow' and 'dsrflow'

Having the option to set individually which pins to use for input and output
flow control and which ones should be on/off all the time seem to be a powerful
way to do it, instead of having a "CDTRDSR".

--
Aristeu