linux-serial.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Suggested patch for linux
@ 2008-07-09 23:16 Axel Hosemann
       [not found] ` <487546D5.8050908-3sKltW3hOZofv37vnLkPlQ@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Axel Hosemann @ 2008-07-09 23:16 UTC (permalink / raw)
  To: linux-serial; +Cc: linux-usb

[-- Attachment #1: Type: text/plain, Size: 1465 bytes --]

Dear Sirs,
the support of the serial interface by linux systems nowadays suffers 
from the disadvantage, that hardware handshake is only supported for the 
full duplex mode. That means, that the RTS signal is getting always 
asserted immediately after the serial was opened. So the RTS signal 
under linux, as far as I understood it, carries exactly the same 
information as the DTR line. That means, that there is no half-duplex 
behaviour provided by linux.  A half-duplex  application as e.g. RS-485 
controllers or radio modems  are depending on a different behaviour: The 
serial port asserts DTR after it was opened, but RTS must only be 
asserted, when data has been written to the tx buffer for transmission. 
Stimulated by  the RTS signal, the DCE will then engage the channel for 
transmission and release it, after the RTS has been deasserted when the 
buffer had been sent. This behaviour is up to now not supported by the 
linux serial drivers.
Therefore I make a suggestion for adding the half-duplex support for 
linux kernels by the attached patch, which I  created and tested on a 
UART 16550 compliant  hardware and additionally by means of a ftdi usb 
to serial port adaptor.  The patch was compiled and tested with an 
UBUNTU 2.6.24-19-generic environment.
If you see a chance, to add this functionality for future linux kernels, 
I would be interested in further discussions about this patch.

Regards

Axel Hosemann
Bergstrasse 6f
CH 5644 Auw

[-- Attachment #2: serialHalfDuplex.patch --]
[-- Type: text/x-patch, Size: 11594 bytes --]

diff -urN linux-2.6.24/drivers/serial/serial_core.c linux-2.6.24-new/drivers/serial/serial_core.c
--- linux-2.6.24/drivers/serial/serial_core.c	2008-02-11 06:51:11.000000000 +0100
+++ linux-2.6.24-new/drivers/serial/serial_core.c	2008-07-07 22:36:16.000000000 +0200
@@ -75,6 +75,9 @@
 	 */
 	BUG_ON(!info);
 	tasklet_schedule(&info->tlet);
+#ifdef RTSHDX
+	wake_up_interruptible(&port->rts_wait);
+#endif
 }
 
 static void uart_stop(struct tty_struct *tty)
@@ -181,8 +184,15 @@
 			 * Setup the RTS and DTR signals once the
 			 * port is open and ready to respond.
 			 */
-			if (info->tty->termios->c_cflag & CBAUD)
+			if (info->tty->termios->c_cflag & CBAUD){
+#ifdef RTSHDX
+				port->toggleRTS = false;
+				uart_set_mctrl(port, TIOCM_DTR);
+				uart_clear_mctrl(port, TIOCM_RTS);
+#else
 				uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+#endif
+			}
 		}
 
 		if (info->flags & UIF_CTS_FLOW) {
@@ -473,6 +483,47 @@
 	uart_start(tty);
 }
 
+#ifdef RTSHDX
+static void uart_wait_infinite_until_sent(struct tty_struct *tty)
+{
+	struct uart_state *state = tty->driver_data;
+	struct uart_port *port = state->port;
+	unsigned long char_time;
+
+	BUG_ON(!kernel_locked());
+
+	char_time = (port->timeout - HZ/50) / port->fifosize;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	
+	if (port->type == PORT_UNKNOWN || port->fifosize == 0)
+		return;
+
+	/*
+	 * Check whether the transmitter is empty every 'char_time'.
+	 */
+	while (!port->ops->tx_empty(port)) {
+		msleep_interruptible(jiffies_to_msecs(char_time));
+	}
+	//wait again until shift register is empty
+	msleep_interruptible(jiffies_to_msecs(char_time));
+	set_current_state(TASK_RUNNING); /* might not be needed */
+}
+
+static void simplified_sleep_on(wait_queue_head_t *queue)
+{
+	wait_queue_t wait;
+
+	init_waitqueue_entry(&wait, current);
+	current->state = TASK_INTERRUPTIBLE;
+
+	add_wait_queue(queue, &wait);
+	schedule();
+	remove_wait_queue (queue, &wait);
+}
+#endif
+
 static int
 uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
@@ -497,6 +548,9 @@
 	if (!circ->buf)
 		return 0;
 
+#ifdef RTSHDX
+	uart_set_mctrl(port, TIOCM_RTS);
+#endif
 	spin_lock_irqsave(&port->lock, flags);
 	while (1) {
 		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
@@ -513,6 +567,16 @@
 	spin_unlock_irqrestore(&port->lock, flags);
 
 	uart_start(tty);
+#ifdef RTSHDX
+	if(port->toggleRTS){
+		//first wait until the device indicates transmission started
+		simplified_sleep_on(&port->rts_wait);
+		//second wait until the device indicates transmission done
+		uart_wait_infinite_until_sent(tty);
+		//now we are ready to deassert RTS
+		uart_clear_mctrl(port, TIOCM_RTS);
+	}
+#endif	
 	return ret;
 }
 
@@ -1143,6 +1207,15 @@
 	unsigned int cflag = tty->termios->c_cflag;
 
 	BUG_ON(!kernel_locked());
+#ifdef RTSHDX
+	state->port->toggleRTS = tty->termios->c_lflag & RTSHDX ? true : false;
+	if(state->port->toggleRTS){
+		uart_clear_mctrl(state->port, TIOCM_RTS);
+	}
+	else {
+		uart_set_mctrl(state->port, TIOCM_RTS);
+	}
+#endif	
 
 	/*
 	 * These are the bits that are used to setup various
@@ -1167,8 +1240,14 @@
 	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
 		unsigned int mask = TIOCM_DTR;
 		if (!(cflag & CRTSCTS) ||
-		    !test_bit(TTY_THROTTLED, &tty->flags))
+		    !test_bit(TTY_THROTTLED, &tty->flags)){
+#ifdef RTSHDX
+			if(!state->port->toggleRTS)
+				mask |= TIOCM_RTS;
+#else	
 			mask |= TIOCM_RTS;
+#endif	
+		}
 		uart_set_mctrl(state->port, mask);
 	}
 
@@ -1413,8 +1492,15 @@
 		/*
 		 * And finally enable the RTS and DTR signals.
 		 */
-		if (tty->termios->c_cflag & CBAUD)
+		if (tty->termios->c_cflag & CBAUD){
+#ifdef RTSHDX
+			//uart_update_mctrl(port,TIOCM_DTR,TIOCM_RTS);
+			uart_clear_mctrl(port, TIOCM_RTS);
+			uart_set_mctrl(port, TIOCM_DTR);
+#else
 			uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+#endif
+		}		
 	}
 }
 
@@ -1527,6 +1613,9 @@
 		if (state->info) {
 			init_waitqueue_head(&state->info->open_wait);
 			init_waitqueue_head(&state->info->delta_msr_wait);
+#ifdef RTSHDX
+			init_waitqueue_head(&state->port->rts_wait);
+#endif
 
 			/*
 			 * Link the info into the other structures.
diff -urN linux-2.6.24/drivers/usb/serial/ftdi_sio.c linux-2.6.24-new/drivers/usb/serial/ftdi_sio.c
--- linux-2.6.24/drivers/usb/serial/ftdi_sio.c	2008-02-11 06:51:11.000000000 +0100
+++ linux-2.6.24-new/drivers/usb/serial/ftdi_sio.c	2008-07-07 22:40:30.000000000 +0200
@@ -301,6 +301,12 @@
 	unsigned long tx_bytes;
 	unsigned long tx_outstanding_bytes;
 	unsigned long tx_outstanding_urbs;
+#ifdef RTSHDX
+	unsigned char charLen;
+	bool toggleRTS;
+	char extended_status;
+	wait_queue_head_t rts_wait; // Used for blocking write
+#endif
 };
 
 /* struct ftdi_sio_quirk is used by devices requiring special attention. */
@@ -722,6 +728,20 @@
 	 return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
 }
 
+#ifdef RTSHDX
+static void simplified_sleep_on(wait_queue_head_t *queue)
+{
+	wait_queue_t wait;
+
+	init_waitqueue_entry(&wait, current);
+	current->state = TASK_INTERRUPTIBLE;
+
+	add_wait_queue(queue, &wait);
+	schedule();
+	remove_wait_queue (queue, &wait);
+}
+#endif
+
 #define set_mctrl(port, set)		update_mctrl((port), (set), 0)
 #define clear_mctrl(port, clear)	update_mctrl((port), 0, (clear))
 
@@ -1221,6 +1241,9 @@
 	spin_lock_init(&priv->rx_lock);
 	spin_lock_init(&priv->tx_lock);
         init_waitqueue_head(&priv->delta_msr_wait);
+#ifdef RTSHDX
+	init_waitqueue_head(&priv->rts_wait);
+#endif
 	/* This will push the characters through immediately rather
 	   than queue a task to deliver them */
 	priv->flags = ASYNC_LOW_LATENCY;
@@ -1372,8 +1395,13 @@
 	/* FIXME: Flow control might be enabled, so it should be checked -
 	   we have no control of defaults! */
 	/* Turn on RTS and DTR since we are not flow controlling by default */
+#ifdef RTSHDX
+	priv->toggleRTS = false;
+	set_mctrl(port, TIOCM_DTR);
+	clear_mctrl(port, TIOCM_RTS);
+#else
 	set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-
+#endif
 	/* Not throttled */
 	spin_lock_irqsave(&priv->rx_lock, flags);
 	priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
@@ -1453,7 +1481,9 @@
 	int status;
 	int transfer_size;
 	unsigned long flags;
-
+#ifdef RTSHDX
+  int baud;
+#endif
 	dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
 
 	if (count == 0) {
@@ -1529,6 +1559,9 @@
 		      usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
 		      buffer, transfer_size,
 		      ftdi_write_bulk_callback, port);
+#ifdef RTSHDX
+	set_mctrl(port, TIOCM_RTS);
+#endif
 
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status) {
@@ -1545,10 +1578,25 @@
 	/* we are done with this urb, so let the host driver
 	 * really free it when it is finished with it */
 	usb_free_urb(urb);
+#ifdef RTSHDX
+	if(priv->toggleRTS){
+		priv->extended_status &= (~FTDI_RS_TEMT);
+		while((priv!=NULL)&&(!(priv->extended_status & FTDI_RS_TEMT))){
+			simplified_sleep_on(&priv->rts_wait);
+		}
+		baud = tty_get_baud_rate(port->tty);      
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(usecs_to_jiffies((2000000 * priv->charLen) / baud));
+		clear_mctrl(port, TIOCM_RTS);
+	}
+#endif
 
 	dbg("%s write returning: %d", __FUNCTION__, count);
 	return count;
 error:
+#ifdef RTSHDX
+	clear_mctrl(port, TIOCM_RTS);
+#endif
 	usb_free_urb(urb);
 error_no_urb:
 	kfree (buffer);
@@ -1769,12 +1817,22 @@
 		/* N.B. packet may be processed more than once, but differences
 		 * are only processed once.  */
 		if (priv != NULL) {
+#ifdef RTSHDX
+			char new_ext_status;
+#endif      
 			char new_status = data[packet_offset+0] & FTDI_STATUS_B0_MASK;
 			if (new_status != priv->prev_status) {
 				priv->diff_status |= new_status ^ priv->prev_status;
 				wake_up_interruptible(&priv->delta_msr_wait);
 				priv->prev_status = new_status;
 			}
+#ifdef RTSHDX
+			new_ext_status = data[packet_offset+1] & FTDI_RS_TEMT;
+			if ((new_ext_status != (priv->extended_status & FTDI_RS_TEMT)) && (new_ext_status != 0)){
+				priv->extended_status |= new_ext_status;
+				wake_up_interruptible(&priv->rts_wait);
+			}
+#endif
 		}
 
 		length = min(PKTSZ, urb->actual_length-packet_offset)-2;
@@ -1940,6 +1998,9 @@
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	struct ktermios *termios = port->tty->termios;
 	unsigned int cflag = termios->c_cflag;
+#ifdef RTSHDX
+	unsigned int lflag = termios->c_lflag;
+#endif
 	__u16 urb_value; /* will hold the new flags */
 	char buf[1]; /* Perhaps I should dynamically alloc this? */
 
@@ -1974,25 +2035,67 @@
 
 	/* Set number of data bits, parity, stop bits */
 
+#ifdef RTSHDX
+	priv->charLen = 1;
+#endif      
 	termios->c_cflag &= ~CMSPAR;
 
 	urb_value = 0;
 	urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
 		      FTDI_SIO_SET_DATA_STOP_BITS_1);
+#ifdef RTSHDX
+	priv->charLen += cflag & CSTOPB ? 2 : 1;
+#endif      
 	urb_value |= (cflag & PARENB ?
 		      (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
 		       FTDI_SIO_SET_DATA_PARITY_EVEN) :
 		      FTDI_SIO_SET_DATA_PARITY_NONE);
-	if (cflag & CSIZE) {
-		switch (cflag & CSIZE) {
-		case CS5: urb_value |= 5; dbg("Setting CS5"); break;
-		case CS6: urb_value |= 6; dbg("Setting CS6"); break;
-		case CS7: urb_value |= 7; dbg("Setting CS7"); break;
-		case CS8: urb_value |= 8; dbg("Setting CS8"); break;
+#ifdef RTSHDX
+	priv->charLen += cflag & PARENB ? 1 : 0;
+#endif      
+	if (cflag & CSIZE){
+		switch (cflag & CSIZE){
+		case CS5:
+#ifdef RTSHDX
+			priv->charLen += 5;
+#endif      
+			urb_value |= 5;
+			dbg("Setting CS5");
+			break;
+		case CS6:
+#ifdef RTSHDX
+			priv->charLen += 6;
+#endif      
+			urb_value |= 6;
+			dbg("Setting CS6");
+			break;
+		case CS7:
+#ifdef RTSHDX
+			priv->charLen += 7;
+#endif      
+			urb_value |= 7;
+			dbg("Setting CS7");
+			break;
+		case CS8:
+#ifdef RTSHDX
+			priv->charLen += 8;
+#endif      
+			urb_value |= 8;
+			dbg("Setting CS8");
+			break;
 		default:
 			err("CSIZE was set but not CS5-CS8");
 		}
 	}
+#ifdef RTSHDX
+	if(lflag & RTSHDX){
+		priv->toggleRTS = true;
+	}
+	else{
+		priv->toggleRTS = false;
+		set_mctrl(port, TIOCM_RTS);
+	}
+#endif
 
 	/* This is needed by the break command since it uses the same command - but is
 	 *  or'ed with this value  */
@@ -2025,7 +2128,17 @@
 		}
 		/* Ensure RTS and DTR are raised when baudrate changed from 0 */
 		if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) {
+#ifdef RTSHDX
+			set_mctrl(port, TIOCM_DTR);
+			if(priv->toggleRTS){
+				clear_mctrl(port, TIOCM_RTS);
+			}
+			else{
+				set_mctrl(port, TIOCM_RTS);
+			}
+#else
 			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+#endif
 		}
 	}
 
diff -urN linux-2.6.24/include/asm-x86/termbits.h linux-2.6.24-new/include/asm-x86/termbits.h
--- linux-2.6.24/include/asm-x86/termbits.h	2008-02-11 06:51:11.000000000 +0100
+++ linux-2.6.24-new/include/asm-x86/termbits.h	2008-06-15 00:24:00.000000000 +0200
@@ -176,6 +176,7 @@
 #define ECHOPRT	0002000
 #define ECHOKE	0004000
 #define FLUSHO	0010000
+#define RTSHDX  0020000
 #define PENDIN	0040000
 #define IEXTEN	0100000
 
diff -urN linux-2.6.24/include/linux/serial_core.h linux-2.6.24-new/include/linux/serial_core.h
--- linux-2.6.24/include/linux/serial_core.h	2008-02-11 06:51:11.000000000 +0100
+++ linux-2.6.24-new/include/linux/serial_core.h	2008-06-16 00:28:06.000000000 +0200
@@ -297,6 +297,10 @@
 	unsigned char		suspended;
 	unsigned char		unused[2];
 	void			*private_data;		/* generic platform data pointer */
+#ifdef RTSHDX
+	bool toggleRTS;
+	wait_queue_head_t rts_wait; // Used for blocking write
+#endif	
 };
 
 /*

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
       [not found] ` <487546D5.8050908-3sKltW3hOZofv37vnLkPlQ@public.gmane.org>
@ 2008-07-10  8:59   ` Alan Cox
  2008-07-10 14:16     ` Matt Schulte
  2008-07-10 14:47     ` Grant Edwards
  0 siblings, 2 replies; 11+ messages in thread
From: Alan Cox @ 2008-07-10  8:59 UTC (permalink / raw)
  To: Axel Hosemann
  Cc: linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA

> Stimulated by  the RTS signal, the DCE will then engage the channel for 
> transmission and release it, after the RTS has been deasserted when the 
> buffer had been sent. This behaviour is up to now not supported by the 
> linux serial drivers.

Actually you can drive this behaviour from user space which is what
software like scarabd has done for many years.

> If you see a chance, to add this functionality for future linux kernels, 
> I would be interested in further discussions about this patch.

The big problem is that the kernel does not know what is a "transmission"
it just sees a series of writes to the device. In many cases the
multi-drop or radio systems also need the caller to wait for a
transmission slot either by beacon, by timing or by monitoring the
carrier detect to avoid collisions.

That seems to best be done in user space as the algorithms are quite
variable and some are complex.

Do we really benefit from having this in kernel ?

Alan
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
  2008-07-10  8:59   ` Alan Cox
@ 2008-07-10 14:16     ` Matt Schulte
  2008-07-12 21:49       ` Axel Hosemann
                         ` (2 more replies)
  2008-07-10 14:47     ` Grant Edwards
  1 sibling, 3 replies; 11+ messages in thread
From: Matt Schulte @ 2008-07-10 14:16 UTC (permalink / raw)
  To: Alan Cox; +Cc: Axel Hosemann, linux-serial, linux-usb


> The big problem is that the kernel does not know what is a "transmission"
> it just sees a series of writes to the device. In many cases the
> multi-drop or radio systems also need the caller to wait for a
> transmission slot either by beacon, by timing or by monitoring the
> carrier detect to avoid collisions.
I believe that he is referring to something much simpler than you are 
thinking.  He is talking about 2-wire RS485 transmissions in which the 
RTS signal is used to enable the driver chips just before transmitting 
data and disabling (tri-stating) them just after transmitting data.  
There are some UARTs that have this behavior built into them.
>
> That seems to best be done in user space as the algorithms are quite
> variable and some are complex.
>
> Do we really benefit from having this in kernel ?
The problem that can come up when executing this feature in user-land 
(though not exactly common) is when the hardware on the other end 
responds to your message faster than your user app was able to detect 
that the UART is finished and then toggle RTS.  When this happens both 
ends are trying to drive the line and you have bus contention, lost data 
and possibly damage to the driver chips themselves.

Matt Schulte
Commtech, Inc.
http://www.commtech-fastcom.com




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
  2008-07-10  8:59   ` Alan Cox
  2008-07-10 14:16     ` Matt Schulte
@ 2008-07-10 14:47     ` Grant Edwards
  2008-08-04 13:28       ` Tosoni
  1 sibling, 1 reply; 11+ messages in thread
From: Grant Edwards @ 2008-07-10 14:47 UTC (permalink / raw)
  To: linux-serial; +Cc: linux-usb

On 2008-07-10, Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

>> Stimulated by the RTS signal, the DCE will then engage the
>> channel for transmission and release it, after the RTS has
>> been deasserted when the buffer had been sent. This behaviour
>> is up to now not supported by the linux serial drivers.
>
> Actually you can drive this behaviour from user space

That doesn't generally work.  You often can't respond quickly
enough in user space.  You need to turn the line around within
as little as a few bit-times.  At high baud rates, you simply
can't do that from user space (especially when the UART is
attached via something like USB or Ethernet).

> which is what software like scarabd has done for many years.
>
>> If you see a chance, to add this functionality for future
>> linux kernels, I would be interested in further discussions
>> about this patch.
>
> The big problem is that the kernel does not know what is a
> "transmission" it just sees a series of writes to the device.

"Transmission" is when the UART is sending data (when the shift
register is not empty).

> In many cases the multi-drop or radio systems also need the
> caller to wait for a transmission slot either by beacon, by
> timing or by monitoring the carrier detect to avoid
> collisions.

That's obviously beyond the scope of the serial driver.
Controlling RTS in half-duplex mode isn't.

> That seems to best be done in user space as the algorithms are
> quite variable and some are complex.
>
> Do we really benefit from having this in kernel ?

People who do industrial communications sure would.  I maintain
a couple serial drivers that support half-duplex mode exactly
as described by the OP, and we have to control that feature via
non-standard hacks.

In the past, I added half-duplex mode support into the standard
Linux 16x50 driver, but could never get it to work reliably
across various chipsets (PC motherboard UART designs don't all
seem to set the shift register empty bit at the same time).

If there was at least a standard way to enable half-duplex
mode, it would be easier to support on hardware that correctly
implements RTS control for half-duplex operation.

-- 
Grant Edwards                   grante             Yow! Here we are in America
                                  at               ... when do we collect
                               visi.com            unemployment?


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
  2008-07-10 14:16     ` Matt Schulte
@ 2008-07-12 21:49       ` Axel Hosemann
  2008-07-12 22:33       ` Alan Cox
  2008-07-18 10:19       ` Laurent Pinchart
  2 siblings, 0 replies; 11+ messages in thread
From: Axel Hosemann @ 2008-07-12 21:49 UTC (permalink / raw)
  To: Matt Schulte; +Cc: linux-usb, linux-serial

Dear Matt,
first of all, I must apologise for not being familiar with the mailing 
rules of your organisation. I already received a mail by a female 
developer, who was annoyed by me addressing her as "Dear Sirs". Oops! 
I'm sorry.
 From your reply I see, that you understood the reason for the suggested 
patch: I try to port a half duplex application from Windows to Linux, 
which on one hand controls a radio modem by means of a 2 wire RS-485 
bus, and on the other hand exchanges payload data over the half duplex 
radio channel across an asynchronous port. There is no chance for me 
doing that  without this patch, because Linux does not support a feature 
similar to the Windows "RTS_CONTROL_TOGGLE" option.
To the problem you mentioned. Yes, your right: If the RS-485 slave 
device would reply a request with hardware timings within a few 
microseconds, a collision would occur. This would certainly not destroy 
the RS-485 chips, because they are generally protected against these 
collision situations. But theoretically the application would not work, 
when the slave would reply faster, than the PC could release the RTS 
signal.  In practice, I did not face this situation (yet!) Probably 
because the receiving slave needs a micro controller itself, checking 
the checksum, interpreting the request and preparing the response. But 
the problem persists: The OS controlled deassertion of the RTS signal 
may be too slow for fast RS-485 slaves. Anyway, up to now, I had no 
problems with that issue with the mentioned Windows application. But 
when I'm back from my holydays I will do some measurements to compare 
the timing between the Windows application and the suggested Linux patch.
For radio modem transmission, there will be no problem at all: Radio 
modems will always utilise FEC functionalities, which imply interleaving 
and deinterleaving delays. The deinterleaving delay of the receiver is 
in the range of hundreds of milliseconds. Even on legacy PC hardware 
platforms, the OS should be able to deassert RTS in time.
However, the half duplex feature could extend the Linux functionality. I 
read in a few forum threads, that there would be a demand for this 
functionality besides my personal interests.

Best Regards
Axel Hosemann


Matt Schulte wrote:
>
>> The big problem is that the kernel does not know what is a 
>> "transmission"
>> it just sees a series of writes to the device. In many cases the
>> multi-drop or radio systems also need the caller to wait for a
>> transmission slot either by beacon, by timing or by monitoring the
>> carrier detect to avoid collisions.
> I believe that he is referring to something much simpler than you are 
> thinking.  He is talking about 2-wire RS485 transmissions in which the 
> RTS signal is used to enable the driver chips just before transmitting 
> data and disabling (tri-stating) them just after transmitting data.  
> There are some UARTs that have this behavior built into them.
>>
>> That seems to best be done in user space as the algorithms are quite
>> variable and some are complex.
>>
>> Do we really benefit from having this in kernel ?
> The problem that can come up when executing this feature in user-land 
> (though not exactly common) is when the hardware on the other end 
> responds to your message faster than your user app was able to detect 
> that the UART is finished and then toggle RTS.  When this happens both 
> ends are trying to drive the line and you have bus contention, lost 
> data and possibly damage to the driver chips themselves.
>
> Matt Schulte
> Commtech, Inc.
> http://www.commtech-fastcom.com
>
>
>
>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
  2008-07-10 14:16     ` Matt Schulte
  2008-07-12 21:49       ` Axel Hosemann
@ 2008-07-12 22:33       ` Alan Cox
  2008-07-15 20:43         ` Matt Schulte
  2008-07-18 10:19       ` Laurent Pinchart
  2 siblings, 1 reply; 11+ messages in thread
From: Alan Cox @ 2008-07-12 22:33 UTC (permalink / raw)
  To: Matt Schulte; +Cc: Axel Hosemann, linux-serial, linux-usb

On Thu, 10 Jul 2008 09:16:40 -0500
> I believe that he is referring to something much simpler than you are 
> thinking.  He is talking about 2-wire RS485 transmissions in which the 
> RTS signal is used to enable the driver chips just before transmitting 

Its all the same thing. And actually the radios are often RS485

> > That seems to best be done in user space as the algorithms are quite
> > variable and some are complex.

> > Do we really benefit from having this in kernel ?
> The problem that can come up when executing this feature in user-land 
> (though not exactly common) is when the hardware on the other end 
> responds to your message faster than your user app was able to detect 
> that the UART is finished and then toggle RTS.  When this happens both 
> ends are trying to drive the line and you have bus contention, lost data 
> and possibly damage to the driver chips themselves.

The chips are quite safe. Can we stick to real reasons.

In terms of performance you can manage RTS with a real time application
if need be and that will give you very close to kernel side response time.

Alan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
  2008-07-12 22:33       ` Alan Cox
@ 2008-07-15 20:43         ` Matt Schulte
       [not found]           ` <1860bbce0807151343rf5cf4apecdc422ba747dd7d-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Matt Schulte @ 2008-07-15 20:43 UTC (permalink / raw)
  To: Alan Cox; +Cc: Axel Hosemann, linux-serial, linux-usb

> > > Do we really benefit from having this in kernel ?
> > The problem that can come up when executing this feature in user-land
> > (though not exactly common) is when the hardware on the other end
> > responds to your message faster than your user app was able to detect
> > that the UART is finished and then toggle RTS.  When this happens both
> > ends are trying to drive the line and you have bus contention, lost data
> > and possibly damage to the driver chips themselves.
>
> The chips are quite safe. Can we stick to real reasons.
>
> In terms of performance you can manage RTS with a real time application
> if need be and that will give you very close to kernel side response time.
>
> Alan

I apologize if this is a duplicate to anyone, but I've been trying to
get my response through to the board and kept getting rejected, I
think this one will make it through...

The chips may or may not be safe, that isn't the point.  There are
real world applications where response time is an issue and meeting
these criteria is sometimes impossible from a user application.
Switching to an RTOS is certainly an option, it would very likely
allow you to manage RTS withing spec.  However this might not be very
practical for many users.  I suppose another option is to switch to a
serial card that uses a UART that has this capability built in.  I
don't want to sound like an advertisement, but several of my line of
Fastcom serial cards have this feature, where the RS485 gating signal
is governed autonomously by the UART itself.

Matt Schulte
Commtech, Inc.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
       [not found]           ` <1860bbce0807151343rf5cf4apecdc422ba747dd7d-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2008-07-15 20:46             ` Alan Cox
  0 siblings, 0 replies; 11+ messages in thread
From: Alan Cox @ 2008-07-15 20:46 UTC (permalink / raw)
  To: Matt Schulte
  Cc: Axel Hosemann, linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA

> The chips may or may not be safe, that isn't the point.  There are
> real world applications where response time is an issue and meeting
> these criteria is sometimes impossible from a user application.
> Switching to an RTOS is certainly an option, it would very likely

Firstly: Linux has an RT patch and its expected to get merged soon
Second: Linux has RT processes already
Third: A non RT Linux kernel space and user space will not give much
different performance

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
  2008-07-10 14:16     ` Matt Schulte
  2008-07-12 21:49       ` Axel Hosemann
  2008-07-12 22:33       ` Alan Cox
@ 2008-07-18 10:19       ` Laurent Pinchart
  2008-07-18 13:55         ` Grant Edwards
  2 siblings, 1 reply; 11+ messages in thread
From: Laurent Pinchart @ 2008-07-18 10:19 UTC (permalink / raw)
  To: Matt Schulte; +Cc: Alan Cox, Axel Hosemann, linux-serial, linux-usb

[-- Attachment #1: Type: text/plain, Size: 4206 bytes --]

On Thursday 10 July 2008, Matt Schulte wrote:
> 
> > The big problem is that the kernel does not know what is a "transmission"
> > it just sees a series of writes to the device. In many cases the
> > multi-drop or radio systems also need the caller to wait for a
> > transmission slot either by beacon, by timing or by monitoring the
> > carrier detect to avoid collisions.
> I believe that he is referring to something much simpler than you are 
> thinking.  He is talking about 2-wire RS485 transmissions in which the 
> RTS signal is used to enable the driver chips just before transmitting 
> data and disabling (tri-stating) them just after transmitting data.  
> There are some UARTs that have this behavior built into them.

And that feature is currently not supported by Linux, even with UARTs that have hardware support for "Auto RS485" mode, such as the 8250-compatible XR16C2850.

The issue is that no flag is defined for the c_cflag field of the termios structure to enable that feature. The following patch is an example of what would be required.

-----------------------------------------------------------------------------
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 62a2e49..a1351d5 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2071,6 +2071,20 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
 	if (up->port.type == PORT_16750)
 		serial_outp(up, UART_FCR, fcr);
 
+#ifdef CARTS
+	/* Auto RS485 Direction Control on 16850 UARTs */
+	if (up->port.type == PORT_16850) {
+		unsigned char fctr;
+
+		serial_outp(up, UART_LCR, 0xbf);
+		fctr = serial_inp(up, UART_FCTR) & ~UART_FCTR_RS485;
+		if (termios->c_cflag & CARTS)
+			fctr |= UART_FCTR_RS485;
+		serial_outp(up, UART_FCTR, fctr);
+		serial_outp(up, UART_LCR, 0);
+	}
+#endif
+
 	serial_outp(up, UART_LCR, cval);		/* reset DLAB */
 	up->lcr = cval;					/* Save LCR */
 	if (up->port.type != PORT_16750) {
diff --git a/include/asm-powerpc/termbits.h b/include/asm-powerpc/termbits.h
index 5e79198..7b7ee27 100644
--- a/include/asm-powerpc/termbits.h
+++ b/include/asm-powerpc/termbits.h
@@ -166,6 +166,7 @@ struct ktermios {
 #define HUPCL	00040000
 
 #define CLOCAL	00100000
+#define CARTS	  004000000000		/* auto RTS control */
 #define CMSPAR	  010000000000		/* mark or space (stick) parity */
 #define CRTSCTS	  020000000000		/* flow control */
 
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 3c8a6aa..3db78cc 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -188,6 +188,7 @@
 #define UART_FCTR_RTS_8DELAY	0x03
 #define UART_FCTR_IRDA		0x04  /* IrDa data encode select */
 #define UART_FCTR_TX_INT	0x08  /* Tx interrupt type select */
+#define UART_FCTR_RS485		0x08  /* Auto RS485 direction control */
 #define UART_FCTR_TRGA		0x00  /* Tx/Rx 550 trigger table select */
 #define UART_FCTR_TRGB		0x10  /* Tx/Rx 650 trigger table select */
 #define UART_FCTR_TRGC		0x20  /* Tx/Rx 654 trigger table select */
-----------------------------------------------------------------------------

As we need a new flag which isn't Posix-compliant as far as I know, the scope of this change can be broader than just the Linux kernel.

Would the above patch be acceptable (I'm open to changes to the CARTS name) as-is, or does it have to be discussed with userspace developers first ?

> > That seems to best be done in user space as the algorithms are quite
> > variable and some are complex.
> >
> > Do we really benefit from having this in kernel ?
> The problem that can come up when executing this feature in user-land 
> (though not exactly common) is when the hardware on the other end 
> responds to your message faster than your user app was able to detect 
> that the UART is finished and then toggle RTS.  When this happens both 
> ends are trying to drive the line and you have bus contention, lost data 
> and possibly damage to the driver chips themselves.

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

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: Suggested patch for linux
  2008-07-18 10:19       ` Laurent Pinchart
@ 2008-07-18 13:55         ` Grant Edwards
  0 siblings, 0 replies; 11+ messages in thread
From: Grant Edwards @ 2008-07-18 13:55 UTC (permalink / raw)
  To: linux-serial; +Cc: linux-usb

On 2008-07-18, Laurent Pinchart <laurentp@cse-semaphore.com> wrote:

>> I believe that he is referring to something much simpler than
>> you are thinking.  He is talking about 2-wire RS485
>> transmissions in which the RTS signal is used to enable the
>> driver chips just before transmitting data and disabling
>> (tri-stating) them just after transmitting data.  There are
>> some UARTs that have this behavior built into them.
>
> And that feature is currently not supported by Linux, even
> with UARTs that have hardware support for "Auto RS485" mode,
> such as the 8250-compatible XR16C2850.
>
> The issue is that no flag is defined for the c_cflag field of
> the termios structure to enable that feature. The following
> patch is an example of what would be required.

I'd definitely be in favor of such a flag. It sucks having to
resort to various hacks to control support of that feature in
Linux serial drivers.

-- 
Grant Edwards                   grante             Yow! In Newark the
                                  at               laundromats are open 24
                               visi.com            hours a day!


^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: Suggested patch for linux
  2008-07-10 14:47     ` Grant Edwards
@ 2008-08-04 13:28       ` Tosoni
  0 siblings, 0 replies; 11+ messages in thread
From: Tosoni @ 2008-08-04 13:28 UTC (permalink / raw)
  To: 'Grant Edwards', linux-serial

> -----Original Message-----
> From: Grant Edwards
> Sent: Thursday, July 10, 2008 4:48 PM

...
>
> On 2008-07-10, Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
...
> > Do we really benefit from having this in kernel ?
>
> People who do industrial communications sure would.  I maintain
> a couple serial drivers that support half-duplex mode exactly
> as described by the OP, and we have to control that feature via
> non-standard hacks.
...

I fully agree with Grant Edwards. I, as well, have been myself maintaining
two serial drivers that support half-duplex mode exactly as described, and I
have to control that feature via non-standard hacks !!!
I have been porting them over and over again with each Linux version and
subversion, since Linux 2.2, and there IS a demand for it.

About the benefit to have this in the kernel: well, we would be enabled to
implement it for any UART, not just the 16550 series !

Now, about Linux RT and response times: The TXD-to-RTS delay must be as
short as possible. To do this, several UARTS i.e. (Ox950) have a special
mode. How could you do this in a user land program for any baud rate ? I
speak about baud rates up to 2 Mbps, they are in use nowadays on
RS2422/RS485 lines.

Really, I would like AT LEAST some commonly defined way to activate this
behaviour. Russell King once suggested to create a line discipline to handle
the RTS, but even like this we need a way (an ioctl) to activate the
behaviour in the UART driver, to make it independent from the specific UART.

JP Tosoni
Acksys



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2008-08-04 13:55 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-09 23:16 Suggested patch for linux Axel Hosemann
     [not found] ` <487546D5.8050908-3sKltW3hOZofv37vnLkPlQ@public.gmane.org>
2008-07-10  8:59   ` Alan Cox
2008-07-10 14:16     ` Matt Schulte
2008-07-12 21:49       ` Axel Hosemann
2008-07-12 22:33       ` Alan Cox
2008-07-15 20:43         ` Matt Schulte
     [not found]           ` <1860bbce0807151343rf5cf4apecdc422ba747dd7d-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-07-15 20:46             ` Alan Cox
2008-07-18 10:19       ` Laurent Pinchart
2008-07-18 13:55         ` Grant Edwards
2008-07-10 14:47     ` Grant Edwards
2008-08-04 13:28       ` Tosoni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).