Suggested patch for linux
Subsystems (3)
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
drivers/serial/serial_core.c +92 -3
@@ -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.
drivers/usb/serial/ftdi_sio.c +121 -8
220 lines not on this page · raw message
include/asm-x86/termbits.h +1 -0
@@ -176,6 +176,7 @@#define ECHOPRT 0002000#define ECHOKE 0004000#define FLUSHO 0010000 +#define RTSHDX 0020000#define PENDIN 0040000#define IEXTEN 0100000
include/linux/serial_core.h +4 -0
@@ -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 };/*
Quoted 4 lines
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.
Quoted 2 lines
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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 6 lines
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.
Quoted 5 lines
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
Quoted 6 lines · Alan Cox
Quoted 4 lines
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).
Quoted 8 lines
which is what software like scarabd has done for many years.
Quoted 3 lines
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).
Quoted 4 lines
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.
Quoted 4 lines
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.
Signature · 3 lines
Grant Edwards grante Yow! Here we are in America
at ... when do we collect
visi.com unemployment?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
Quoted 21 lines · Matt Schulte
Quoted 6 lines
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.
Quoted 5 lines
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
On Thu, 10 Jul 2008 09:16:40 -0500
Quoted 3 lines
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
Quoted 10 lines
Quoted 4 lines
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
Quoted 8 lines
Quoted 7 lines
Quoted 1 line
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.
Quoted 6 lines
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.
Quoted 4 lines
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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 11 lines · Matt Schulte
Quoted 6 lines
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.
-----------------------------------------------------------------------------
drivers/serial/8250.c +14 -0
@@ -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 ) {
include/asm-powerpc/termbits.h +1 -0
@@ -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 */
include/linux/serial_reg.h +1 -0
@@ -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 ?
Quoted 10 lines
Quoted 4 lines
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,
Signature · 9 lines
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
Quoted 7 lines · Laurent Pinchart
Quoted 6 lines
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.
Quoted 7 lines
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_cflagfield 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.
Signature · 3 lines
Grant Edwards grante Yow! In Newark the
at laundromats are open 24
visi.com hours a day!Quoted 3 lines
-----Original Message-----
From: Grant Edwards
Sent: Thursday, July 10, 2008 4:48 PM
...
Quoted 2 lines · Alan Cox
...
Quoted 6 lines
Quoted 1 line
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