Public bug reported:
Use 2 instances of an app that shows the pinout signals (DTR, DSR, RTS, CTS).
- 1: /dev/ttyS0 (some UART, integrated in the PC)
- 2: /dev/ttyUSB0 (Moxa UPort 1250, using Linux native driver)
Link both ports with a null-modem cable.
- Open 1 (ttyS0): DTR and RTS are ON.
- Open 2 (ttyUSB0): DSR and CTS are OFF.
- Close and reopen port for 1: on 2, DSR and CTS are ON.
You can also try to close and re-open 2: DSR and CTS are OFF.
Also try to close and re-open 1: DSR and CTS are ON.
Behavior of 1 (ttyS0) is correct.
Behavior of 2 (ttyUSB0) is wrong.
------------------------------------------------------------
In my case, once port is open, QSerialPort::pinoutSignals() is called.
The Unix implementation calls ioctl():
int arg = 0;
if (::ioctl(descriptor, TIOCMGET, &arg) == -1) {
setError(getSystemError());
return QSerialPort::NoSignal;
}
------------------------------------------------------------
Now look at the Linux native mxuport driver:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/usb/serial/mxuport.c?h=v6.16.7
Line 1301, TIOCMGET should call mxuport_tiocmget():
static int mxuport_tiocmget(struct tty_struct *tty)
{
struct mxuport_port *mxport;
struct usb_serial_port *port = tty->driver_data;
unsigned int result;
unsigned long flags;
unsigned int msr;
unsigned int mcr;
mxport = usb_get_serial_port_data(port);
mutex_lock(&mxport->mutex);
spin_lock_irqsave(&mxport->spinlock, flags);
msr = mxport->msr_state;
mcr = mxport->mcr_state;
spin_unlock_irqrestore(&mxport->spinlock, flags);
mutex_unlock(&mxport->mutex);
result = (((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) | /* 0x002 */
((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) | /* 0x004 */
((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) | /* 0x020 */
((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) | /* 0x040 */
((msr & UART_MSR_RI) ? TIOCM_RI : 0) | /* 0x080 */
((msr & UART_MSR_DSR) ? TIOCM_DSR : 0)); /* 0x100 */
dev_dbg(&port->dev, "%s - 0x%04x\n", __func__, result);
return result;
}
I think that this function only gets cached values.
Now look briefly at mxuport_msr_event():
...
if (rcv_msr_hold & UART_MSR_CTS) {
mxport->msr_state |= UART_MSR_CTS;
dev_dbg(&port->dev, "%s - CTS high\n", __func__);
} else {
mxport->msr_state &= ~UART_MSR_CTS;
dev_dbg(&port->dev, "%s - CTS low\n", __func__);
}
// same for UART_MSR_DSR and UART_MSR_DCD
...
if (rcv_msr_event &
(SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD)) {
if (rcv_msr_event & SERIAL_EV_CTS) {
port->icount.cts++;
dev_dbg(&port->dev, "%s - CTS change\n", __func__);
}
if (rcv_msr_event & SERIAL_EV_DSR) {
port->icount.dsr++;
dev_dbg(&port->dev, "%s - DSR change\n", __func__);
}
if (rcv_msr_event & SERIAL_EV_RLSD) {
port->icount.dcd++;
dev_dbg(&port->dev, "%s - DCD change\n", __func__);
}
wake_up_interruptible(&port->port.delta_msr_wait);
}
This function is called by mxuport_process_read_urb_event():
/*
* When something interesting happens, modem control lines XON/XOFF
* etc, the device sends an event. Process these events.
*/
static void mxuport_process_read_urb_event(struct usb_serial_port *port,
u8 buf[4], u32 event)
{
dev_dbg(&port->dev, "%s - receive event : %04x\n", __func__, event);
switch (event) {
case UPORT_EVENT_SEND_NEXT:
/*
* Sent as part of the flow control on device buffers.
* Not currently used.
*/
break;
case UPORT_EVENT_MSR:
mxuport_msr_event(port, buf);
break;
case UPORT_EVENT_LSR:
mxuport_lsr_event(port, buf);
break;
case UPORT_EVENT_MCR:
/*
* Event to indicate a change in XON/XOFF from the
* peer. Currently not used. We just continue
* sending the device data and it will buffer it if
* needed. This event could be used for flow control
* between the host and the device.
*/
break;
default:
dev_dbg(&port->dev, "Unexpected event\n");
break;
}
}
Finally, an interesting comment in mxuport_open():
/*
* TODO: use RQ_VENDOR_GET_MSR, once we know what it
* returns.
*/
mxport->msr_state = 0;
--------------------------------------------------------
In the Moxa driver mxuport-kernel-6 in mx-uport.c, in mxuport_open():
...
msr_ret = mx_recv_ctrl_urb(port->serial->dev,
RQ_VENDOR_GET_MSR,
0,
mx_port->portno,
&msr_value,
sizeof(msr_value));
if(msr_ret < 0)
mx_port->msr_state = 0;
else
mx_port->msr_state = msr_value;
...
I think that's the missing part in the Linux native driver.
Also, mx_recv_ctrl_urb() is a wrapper around usb_control_msg().
--------------------------------------------------------
To see a version with links and somewhat formatted code, you can look:
https://gitlab.com/scandyna/mdtterminal/-/issues/4
** Affects: ubuntu
Importance: Undecided
Status: New
** Tags: moxa mxuport uport
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2123856
Title:
DSR and CTS pinout signals not reliable after port open with Moxa
UPort
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+bug/2123856/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs