forked from Imagelibrary/rtems
Fix from Eric Norum <eric@skatter.usask.ca>:
"Thomas Doerfler" <td@imd.m.isar.de> wrote:
>
> While implementing/testing the console/termios support for
> PPC403 in RTEMS-4.0.0-beta3, I am stuck at a certain location in
> termios.c:
>
> During "rtems_termios_initialize", the main control data structure
> "*tty" is allocated using malloc(). (Note, that malloc does not
> clear the allocated memory and my BSP does not clear memory during
> startup). Furtheron, a lot of fields of that structure are
> initialized, but the field "rawOutBufState" is not, and therefore
> keeps an arbitrary contents.
>
> When "osend()" is called the first time(with the serial device
> driver working in interrupt mode), termios gets stuck and will not
> call the device drivers output function.
>
> My questions now are:
>
> - anybody already experienced this bug?
> - is it a bug at all or did I do anything fundamentally wrong?
> - is there already a common bugfix for that?
>
> I don't like poking around in other people code, as long as I am
> not absolutely sure, what I do...
Yes, there's a bug there.
I thought that Joel had patched this already, but here's a patch to
fix this. This patch also addresses a concern that many others have
raised regarding enabling and disabling of transmitter interrupts.
First, here's the example I've been using of a simple UART-style
interrupt-driven driver:
===============================================================
void
device_write_routine (int minor, char *buf, int count)
{
UART->control_register &= ~UART_TRANSMITTER_READY;
UART->output_register = *buf;
UART->control_register |= UART_TRANSMIT_INTERRUPT_ENABLE;
}
void
device_transmit_interrupt_routine (int vector)
{
UART->control_register &= ~UART_TRANSMIT_INTERRUPT_ENABLE;
rtems_termios_dequeue_characters (device_ttyp, 1);
}
==============================================================
Several people have expressed their concern about the disable/enable
of transmitter interrupts for every character. On some machines
this disable/enable is an expensive operation. With the attached
patch applied you can write the two routines as:
==============================================================
void
device_write_routine (int minor, char *buf, int count)
{
code_to_clear_transmitter_ready_status ();
if (device_ttyp->rawOutBufState == rob_idle)
code_to_enable_transmitter_interrupts ();
code_to_send_one_character_to_transmitter (*buf);
}
void
device_transmit_interrupt_routine (int vector)
{
rtems_termios_dequeue_characters (device_ttyp, 1);
if (device_ttyp->rawOutBufState == rob_idle)
code_to_disable_transmitter_interrupts ();
}
===============================================================
This commit is contained in:
@@ -213,7 +213,6 @@ rtems_termios_open (
|
||||
}
|
||||
tty->forw = ttyHead;
|
||||
ttyHead = tty;
|
||||
tty->back = NULL;
|
||||
if (ttyTail == NULL)
|
||||
ttyTail = tty;
|
||||
|
||||
@@ -247,9 +246,6 @@ rtems_termios_open (
|
||||
&tty->rawOutBufSemaphore);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (sc);
|
||||
tty->rawOutBufHead = 0;
|
||||
tty->rawOutBufTail = 0;
|
||||
tty->refcount = 0;
|
||||
tty->rawOutBufState = rob_idle;
|
||||
|
||||
/*
|
||||
@@ -265,16 +261,8 @@ rtems_termios_open (
|
||||
&tty->rawInBufSemaphore);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (sc);
|
||||
tty->rawInBufHead = 0;
|
||||
tty->rawInBufTail = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize variables
|
||||
*/
|
||||
tty->column = 0;
|
||||
tty->cindex = tty->ccount = 0;
|
||||
|
||||
/*
|
||||
* Set default parameters
|
||||
*/
|
||||
@@ -481,9 +469,9 @@ osend (const char *buf, int len, struct rtems_termios_tty *tty)
|
||||
tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
|
||||
tty->rawOutBufHead = newHead;
|
||||
if (tty->rawOutBufState == rob_idle) {
|
||||
tty->rawOutBufState = rob_busy;
|
||||
(*tty->device.write)(tty->minor,
|
||||
(char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
|
||||
tty->rawOutBufState = rob_busy;
|
||||
}
|
||||
rtems_interrupt_enable (level);
|
||||
len--;
|
||||
@@ -935,12 +923,12 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
|
||||
/*
|
||||
* Buffer not empty, start tranmitter
|
||||
*/
|
||||
tty->rawOutBufState = rob_busy;
|
||||
if (newTail > tty->rawOutBufHead)
|
||||
nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
|
||||
else
|
||||
nToSend = tty->rawOutBufHead - newTail;
|
||||
(*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
|
||||
tty->rawOutBufState = rob_busy;
|
||||
}
|
||||
tty->rawOutBufTail = newTail;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,6 @@ rtems_termios_open (
|
||||
}
|
||||
tty->forw = ttyHead;
|
||||
ttyHead = tty;
|
||||
tty->back = NULL;
|
||||
if (ttyTail == NULL)
|
||||
ttyTail = tty;
|
||||
|
||||
@@ -247,9 +246,6 @@ rtems_termios_open (
|
||||
&tty->rawOutBufSemaphore);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (sc);
|
||||
tty->rawOutBufHead = 0;
|
||||
tty->rawOutBufTail = 0;
|
||||
tty->refcount = 0;
|
||||
tty->rawOutBufState = rob_idle;
|
||||
|
||||
/*
|
||||
@@ -265,16 +261,8 @@ rtems_termios_open (
|
||||
&tty->rawInBufSemaphore);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (sc);
|
||||
tty->rawInBufHead = 0;
|
||||
tty->rawInBufTail = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize variables
|
||||
*/
|
||||
tty->column = 0;
|
||||
tty->cindex = tty->ccount = 0;
|
||||
|
||||
/*
|
||||
* Set default parameters
|
||||
*/
|
||||
@@ -481,9 +469,9 @@ osend (const char *buf, int len, struct rtems_termios_tty *tty)
|
||||
tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
|
||||
tty->rawOutBufHead = newHead;
|
||||
if (tty->rawOutBufState == rob_idle) {
|
||||
tty->rawOutBufState = rob_busy;
|
||||
(*tty->device.write)(tty->minor,
|
||||
(char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
|
||||
tty->rawOutBufState = rob_busy;
|
||||
}
|
||||
rtems_interrupt_enable (level);
|
||||
len--;
|
||||
@@ -935,12 +923,12 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
|
||||
/*
|
||||
* Buffer not empty, start tranmitter
|
||||
*/
|
||||
tty->rawOutBufState = rob_busy;
|
||||
if (newTail > tty->rawOutBufHead)
|
||||
nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
|
||||
else
|
||||
nToSend = tty->rawOutBufHead - newTail;
|
||||
(*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
|
||||
tty->rawOutBufState = rob_busy;
|
||||
}
|
||||
tty->rawOutBufTail = newTail;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user