2007-08-31 13:42:22

by Michael Westermann

[permalink] [raw]
Subject: DTR/DSR Patch

Hello,

I make driver for Point of Sale Printer, a wide range of Printer use
only a DTR/DSR hardware-handshaking. When I use a handshaking in the
userspace, the Printr has a overrun problem and our customer has a
problem with the tax office.

my Patch relaize a simple DTR/DSR handhake with a small change of the
code. The change auf the userspace is very simple. e.g.


cflags |= CDTRDSR;

The change of the stty tool at 2 lines.

Michael


diff -Nur linux-2.6/drivers/serial/8250.c linux-2.6.dsr_test/drivers/serial/8250.c
--- linux-2.6/drivers/serial/8250.c 2007-08-28 11:31:48.000000000 +0200
+++ linux-2.6.dsr_test/drivers/serial/8250.c 2007-08-31 13:20:57.000000000 +0200
@@ -1400,12 +1400,15 @@
up->port.info != NULL) {
if (status & UART_MSR_TERI)
up->port.icount.rng++;
- if (status & UART_MSR_DDSR)
- up->port.icount.dsr++;
if (status & UART_MSR_DDCD)
uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
- if (status & UART_MSR_DCTS)
- uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+ if (status & (UART_MSR_DCTS|UART_MSR_DDSR)) {
+ if (status & UART_MSR_DDSR)
+ up->port.icount.dsr++;
+ else
+ up->port.icount.cts++;
+ uart_handle_dsr_cts_change(&up->port, status & UART_MSR_CTS, status & UART_MSR_DSR);
+ }

wake_up_interruptible(&up->port.info->delta_msr_wait);
}
diff -Nur linux-2.6/drivers/serial/serial_core.c linux-2.6.dsr_test/drivers/serial/serial_core.c
--- linux-2.6/drivers/serial/serial_core.c 2007-08-28 11:31:48.000000000 +0200
+++ linux-2.6.dsr_test/drivers/serial/serial_core.c 2007-08-31 13:29:22.000000000 +0200
@@ -191,6 +191,13 @@
info->tty->hw_stopped = 1;
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->tty->hw_stopped = 1;
+ spin_unlock_irq(&port->lock);
+ }

info->flags |= UIF_INITIALIZED;

@@ -437,6 +444,11 @@
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
--- linux-2.6/include/asm-i386/termbits.h 2007-05-21 10:37:10.000000000 +0200
+++ linux-2.6.dsr_test/include/asm-i386/termbits.h 2007-08-28 11:58:43.000000000 +0200
@@ -157,6 +157,7 @@
#define B3500000 0010016
#define B4000000 0010017
#define CIBAUD 002003600000
+#define CDTRDSR 004000000000 /* dtrdsr flow control */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */

diff -Nur linux-2.6/include/linux/serial_core.h linux-2.6.dsr_test/include/linux/serial_core.h
--- linux-2.6/include/linux/serial_core.h 2007-08-16 10:30:59.000000000 +0200
+++ linux-2.6.dsr_test/include/linux/serial_core.h 2007-08-30 16:09:55.000000000 +0200
@@ -334,6 +334,7 @@
* Definitions for info->flags. These are _private_ to serial_core, and
* are specific to this structure. They may be queried by low level drivers.
*/
+#define UIF_DSR_FLOW ((__force uif_t) (1 << 22))
#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))
@@ -493,26 +494,27 @@

/**
* uart_handle_cts_change - handle a change of clear-to-send state
+ * when set DTR/DSR and RTS/CTS send only when both lines ok
* @port: uart_port structure for the open port
* @status: new clear to send status, nonzero if active
*/
static inline void
-uart_handle_cts_change(struct uart_port *port, unsigned int status)
+uart_handle_dsr_cts_change(struct uart_port *port, unsigned int status_cts, unsigned int status_dsr)
{
struct uart_info *info = port->info;
struct tty_struct *tty = info->tty;
+ int cts_stop = (info->flags & UIF_CTS_FLOW) && !status_cts;
+ int dsr_stop = (info->flags & UIF_DSR_FLOW) && !status_dsr;

- port->icount.cts++;
-
- if (info->flags & UIF_CTS_FLOW) {
+ if ((info->flags & UIF_CTS_FLOW) || (info->flags & UIF_DSR_FLOW)) {
if (tty->hw_stopped) {
- if (status) {
+ if (!(cts_stop||dsr_stop)) {
tty->hw_stopped = 0;
port->ops->start_tx(port);
uart_write_wakeup(port);
}
} else {
- if (!status) {
+ if (cts_stop||dsr_stop) {
tty->hw_stopped = 1;
port->ops->stop_tx(port);
}
@@ -543,7 +545,7 @@
* 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


2007-09-13 00:39:38

by Andrew Morton

[permalink] [raw]
Subject: Re: DTR/DSR Patch

On Fri, 31 Aug 2007 15:17:41 +0200
Michael Westermann <[email protected]> wrote:

> Hello,
>
> I make driver for Point of Sale Printer, a wide range of Printer use
> only a DTR/DSR hardware-handshaking. When I use a handshaking in the
> userspace, the Printr has a overrun problem and our customer has a
> problem with the tax office.
>
> my Patch relaize a simple DTR/DSR handhake with a small change of the
> code. The change auf the userspace is very simple. e.g.
>
>
> cflags |= CDTRDSR;
>
> The change of the stty tool at 2 lines.
>

googling for CDTRDSR is useful. I see from
http://lkml.org/lkml/2006/12/10/49 that Russell was generally supportive,
but requested changes which afaict you have implemented here?


> --- linux-2.6/include/asm-i386/termbits.h 2007-05-21 10:37:10.000000000 +0200
> +++ linux-2.6.dsr_test/include/asm-i386/termbits.h 2007-08-28 11:58:43.000000000 +0200
> @@ -157,6 +157,7 @@
> #define B3500000 0010016
> #define B4000000 0010017
> #define CIBAUD 002003600000
> +#define CDTRDSR 004000000000 /* dtrdsr flow control */
> #define CMSPAR 010000000000 /* mark or space (stick) parity */
> #define CRTSCTS 020000000000 /* flow control */
>

This will break all architectures except for i386. So for now I guess we
can do this:

--- a/include/linux/termios.h~serial-8250-implement-dtr-dsr-handshaking-fix
+++ a/include/linux/termios.h
@@ -4,4 +4,8 @@
#include <linux/types.h>
#include <asm/termios.h>

+#ifndef CDTRDSR
+#define CDTRDSR 0 /* remove this when all architectures have a definition */
+#endif
+
#endif
_

but that's temporary. If we decide to proceed with this change then we
should add CDTRDSR to each arch's termbits.h. That'll be pretty
straightforward to arrange.

Actually, let's spam them ...

--- a/include/linux/termios.h~serial-8250-implement-dtr-dsr-handshaking-fix
+++ a/include/linux/termios.h
@@ -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
_

2007-09-13 07:49:17

by Russell King

[permalink] [raw]
Subject: Re: DTR/DSR Patch

On Wed, Sep 12, 2007 at 05:38:17PM -0700, Andrew Morton wrote:
> On Fri, 31 Aug 2007 15:17:41 +0200
> Michael Westermann <[email protected]> wrote:
>
> > Hello,
> >
> > I make driver for Point of Sale Printer, a wide range of Printer use
> > only a DTR/DSR hardware-handshaking. When I use a handshaking in the
> > userspace, the Printr has a overrun problem and our customer has a
> > problem with the tax office.
> >
> > my Patch relaize a simple DTR/DSR handhake with a small change of the
> > code. The change auf the userspace is very simple. e.g.
> >
> >
> > cflags |= CDTRDSR;
> >
> > The change of the stty tool at 2 lines.
> >
>
> googling for CDTRDSR is useful. I see from
> http://lkml.org/lkml/2006/12/10/49 that Russell was generally supportive,
> but requested changes which afaict you have implemented here?

Partially implemented - my point 1 seems to have been addressed but not
point 2. Point 2 is rather important, otherwise you can end up with a
port in stopped mode with no way to get it transmitting.

Also, it doesn't seem to be tweaking the DTR signal at all, so how does
it tell the remote end to stop transmitting?

Essentially, the author needs to search for CRTSCTS in serial_core.c and
*carefully* consider whether they need to modify those places as well.
I stress carefully, because at the moment we start the tty whenever
we move from CRTSCTS to no CRTSCTS. If you're moving CRTSCTS->CDTRDSR
then you only want to do this iff DSR is asserted.

--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of: