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.
This commit is contained in:
Sebastian Huber
2017-10-18 07:18:57 +02:00
parent 37eb717f90
commit 67015b617e
2 changed files with 13 additions and 3 deletions

View File

@@ -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,6 +643,12 @@ static bool ns16550_set_attributes(
* Now actually set the chip
*/
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);
/*
@@ -662,6 +669,7 @@ static bool ns16550_set_attributes(
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
rtems_termios_device_lock_release(base, &lock_context);
}
return true;
}

View File

@@ -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;