[rtems commit] dev/serial: Lazy update of NS16550 settings

Sebastian Huber sebh at rtems.org
Wed Oct 18 06:52:49 UTC 2017


Module:    rtems
Branch:    master
Commit:    67015b617e68c97e73266d625bea0edccfa42d44
Changeset: http://git.rtems.org/rtems/commit/?id=67015b617e68c97e73266d625bea0edccfa42d44

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Wed Oct 18 07:18:57 2017 +0200

dev/serial: Lazy update of NS16550 settings

Updates of the line control and baud divisor while transfers are in
progress may lead to unpredictable behaviour on some chips. Perform the
updates only if necessary.

Close #3198.

---

 c/src/libchip/serial/ns16550-context.c | 14 +++++++++++---
 c/src/libchip/serial/ns16550.h         |  2 ++
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/c/src/libchip/serial/ns16550-context.c b/c/src/libchip/serial/ns16550-context.c
index 8901590..3c41978 100644
--- a/c/src/libchip/serial/ns16550-context.c
+++ b/c/src/libchip/serial/ns16550-context.c
@@ -148,6 +148,7 @@ bool ns16550_probe(rtems_termios_device_context *base)
   /* Set the divisor latch and set the baud rate. */
 
   ulBaudDivisor = NS16550_GetBaudDivisor(ctx, ctx->initial_baud);
+  ctx->baud_divisor = ulBaudDivisor;
   ucDataByte = SP_LINE_DLAB;
   (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
 
@@ -161,6 +162,7 @@ bool ns16550_probe(rtems_termios_device_context *base)
   /* Clear the divisor latch and set the character size to eight bits */
   /* with one stop bit and no parity checking. */
   ucDataByte = EIGHT_BITS;
+  ctx->line_control = ucDataByte;
   (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
 
   /* Enable and reset transmit and receive FIFOs. TJA     */
@@ -585,7 +587,6 @@ static bool ns16550_set_attributes(
   uint8_t                 ucLineControl;
   uint32_t                baud_requested;
   ns16550_set_reg         setReg;
-  rtems_interrupt_lock_context lock_context;
 
   pNS16550 = ctx->port;
   setReg   = ctx->set_reg;
@@ -642,7 +643,13 @@ static bool ns16550_set_attributes(
    *  Now actually set the chip
    */
 
-  rtems_termios_device_lock_acquire(base, &lock_context);
+  if (ulBaudDivisor != ctx->baud_divisor || ucLineControl != ctx->line_control) {
+    rtems_interrupt_lock_context lock_context;
+
+    ctx->baud_divisor = ulBaudDivisor;
+    ctx->line_control = ucLineControl;
+
+    rtems_termios_device_lock_acquire(base, &lock_context);
 
     /*
      *  Set the baud rate
@@ -661,7 +668,8 @@ static bool ns16550_set_attributes(
      */
     (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
 
-  rtems_termios_device_lock_release(base, &lock_context);
+    rtems_termios_device_lock_release(base, &lock_context);
+  }
 
   return true;
 }
diff --git a/c/src/libchip/serial/ns16550.h b/c/src/libchip/serial/ns16550.h
index 19ac3f1..4f1b98b 100644
--- a/c/src/libchip/serial/ns16550.h
+++ b/c/src/libchip/serial/ns16550.h
@@ -70,6 +70,8 @@ typedef struct {
   uint32_t initial_baud;
   bool has_fractional_divider_register;
   uint8_t modem_control;
+  uint8_t line_control;
+  uint32_t baud_divisor;
   size_t out_total;
   size_t out_remaining;
   size_t out_current;




More information about the vc mailing list