summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-10-18 07:18:57 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-10-18 07:21:54 +0200
commit67015b617e68c97e73266d625bea0edccfa42d44 (patch)
treef6e41c85af8b358107468568110909e7d13c1222
parentposix: Simplify _POSIX_Threads_Create_extension() (diff)
downloadrtems-67015b617e68c97e73266d625bea0edccfa42d44.tar.bz2
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.
-rw-r--r--c/src/libchip/serial/ns16550-context.c14
-rw-r--r--c/src/libchip/serial/ns16550.h2
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 8901590522..3c419780ae 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 19ac3f1152..4f1b98bf0b 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;