USB: serial: invoke dcd_change ldisc's handler.
authorPaul Chavent <Paul.Chavent@onera.fr>
Mon, 16 Sep 2013 06:41:00 +0000 (08:41 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 26 Sep 2013 16:45:40 +0000 (09:45 -0700)
The DCD pin of the serial port can receive a PPS signal. By calling
the port line discipline dcd handle, this patch allow to monitor PPS
through USB serial devices.

However the performance aren't as good as the uart drivers, so
document this point too.

Signed-off-by: Paul Chavent <paul.chavent@onera.fr>
Acked-by: Rodolfo Giometti <giometti@enneenne.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/pps/pps.txt
drivers/usb/serial/generic.c

index d35dcdd82ff6a6c93b2dae00be717080b9b21cb1..c03b1be5eb1517b7b16cbddd6d2999101020ca53 100644 (file)
@@ -66,6 +66,21 @@ In LinuxPPS the PPS sources are simply char devices usually mapped
 into files /dev/pps0, /dev/pps1, etc..
 
 
+PPS with USB to serial devices
+------------------------------
+
+It is possible to grab the PPS from an USB to serial device. However,
+you should take into account the latencies and jitter introduced by
+the USB stack. Users has reported clock instability around +-1ms when
+synchronized with PPS through USB. This isn't suited for time server
+synchronization.
+
+If your device doesn't report PPS, you can check that the feature is
+supported by its driver. Most of the time, you only need to add a call
+to usb_serial_handle_dcd_change after checking the DCD status (see
+ch341 and pl2303 examples).
+
+
 Coding example
 --------------
 
index 1f31e6b4c2518f262a263bbefdddf5fda6ba9cb6..3a5dac879094a831a349f536b28e6f63d21903db 100644 (file)
@@ -570,6 +570,16 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
 
        dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status);
 
+       if (tty) {
+               struct tty_ldisc *ld = tty_ldisc_ref(tty);
+
+               if (ld) {
+                       if (ld->ops->dcd_change)
+                               ld->ops->dcd_change(tty, status);
+                       tty_ldisc_deref(ld);
+               }
+       }
+
        if (status)
                wake_up_interruptible(&port->open_wait);
        else if (tty && !C_CLOCAL(tty))