DTR/DSR Patch

From: Michael Westermann
Date: Fri Aug 31 2007 - 09:42:23 EST


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

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/