interrupt driven change from Eric Norum

This commit is contained in:
Joel Sherrill
1997-11-15 18:15:36 +00:00
parent a307f79f17
commit d24ceb38f7
8 changed files with 618 additions and 261 deletions

View File

@@ -139,7 +139,8 @@ rtems_status_code rtems_termios_open (
int (*deviceFirstOpen)(int major, int minor, void *arg),
int (*deviceLastClose)(int major, int minor, void *arg),
int (*deviceRead)(int minor),
int (*deviceWrite)(int minor, char *buf, int len)
int (*deviceWrite)(int minor, char *buf, int len),
int deviceOutputUsesInterrupts
);
rtems_status_code rtems_termios_close (void *arg);

View File

@@ -1,20 +1,13 @@
/*
* TERMIOS serial line support
*
* Authors:
* Author:
* W. Eric Norum
* Saskatchewan Accelerator Laboratory
* University of Saskatchewan
* Saskatoon, Saskatchewan, CANADA
* eric@skatter.usask.ca
*
* AND
*
* Katsutoshi Shibuya
* BU Denken Co.,Ltd.
* Sapporo, JAPAN
* shibuya@mxb.meshnet.or.jp
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
@@ -37,9 +30,12 @@
#define CBUFSIZE 256
/*
* The size of the raw input message queue
* The sizes of the raw message buffers.
* On most architectures it is quite a bit more
* efficient if these are powers of two.
*/
#define RAW_BUFFER_SIZE 128
#define RAW_INPUT_BUFFER_SIZE 128
#define RAW_OUTPUT_BUFFER_SIZE 64
/*
* Variables associated with each termios instance.
@@ -89,16 +85,26 @@ struct rtems_termios_tty {
rtems_interval vtimeTicks;
/*
* Raw character buffer
* Raw input character buffer
*/
volatile char rawBuf[RAW_BUFFER_SIZE];
volatile unsigned int rawBufHead;
volatile unsigned int rawBufTail;
rtems_id rawBufSemaphore;
rtems_unsigned32 rawBufSemaphoreOptions;
rtems_interval rawBufSemaphoreTimeout;
rtems_interval rawBufSemaphoreFirstTimeout;
unsigned int rawBufDropped; /* Statistics */
volatile char rawInBuf[RAW_INPUT_BUFFER_SIZE];
volatile unsigned int rawInBufHead;
volatile unsigned int rawInBufTail;
rtems_id rawInBufSemaphore;
rtems_unsigned32 rawInBufSemaphoreOptions;
rtems_interval rawInBufSemaphoreTimeout;
rtems_interval rawInBufSemaphoreFirstTimeout;
unsigned int rawInBufDropped; /* Statistics */
/*
* Raw output character buffer
*/
char outputUsesInterrupts;
volatile char rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];
volatile unsigned int rawOutBufHead;
volatile unsigned int rawOutBufTail;
rtems_id rawOutBufSemaphore;
enum {rob_idle, rob_busy, rob_wait } rawOutBufState;
/*
* Callbacks to device-specific routines
@@ -110,6 +116,29 @@ struct rtems_termios_tty {
static struct rtems_termios_tty *ttyHead, *ttyTail;
static rtems_id ttyMutex;
/*
* Reserve enough resources to open every physical device once.
*/
void
rtems_termios_reserve_resources (
rtems_configuration_table *configuration,
rtems_unsigned32 number_of_devices
)
{
static int first_time = 1;
rtems_api_configuration_table *rtems_config;
if (!configuration)
rtems_fatal_error_occurred (0xFFF0F001);
rtems_config = configuration->RTEMS_api_configuration;
if (!rtems_config)
rtems_fatal_error_occurred (0xFFF0F002);
if (first_time)
rtems_config->maximum_semaphores += 1;
first_time = 0;
rtems_config->maximum_semaphores += (4 * number_of_devices);
}
void
rtems_termios_initialize (void)
{
@@ -141,7 +170,8 @@ rtems_termios_open (
int (*deviceFirstOpen)(int major, int minor, void *arg),
int (*deviceLastClose)(int major, int minor, void *arg),
int (*deviceRead)(int minor),
int (*deviceWrite)(int minor, char *buf, int len)
int (*deviceWrite)(int minor, char *buf, int len),
int deviceOutputUsesInterrupts
)
{
rtems_status_code sc;
@@ -194,6 +224,16 @@ rtems_termios_open (
&tty->osem);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
sc = rtems_semaphore_create (
rtems_build_name ('T', 'R', 'x', c),
0,
RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
RTEMS_NO_PRIORITY,
&tty->rawOutBufSemaphore);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
tty->rawOutBufHead = 0;
tty->rawOutBufTail = 0;
/*
* Set callbacks
@@ -206,11 +246,11 @@ rtems_termios_open (
0,
RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
RTEMS_NO_PRIORITY,
&tty->rawBufSemaphore);
&tty->rawInBufSemaphore);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
tty->rawBufHead = 0;
tty->rawBufTail = 0;
tty->rawInBufHead = 0;
tty->rawInBufTail = 0;
}
/*
@@ -218,6 +258,7 @@ rtems_termios_open (
*/
tty->column = 0;
tty->cindex = tty->ccount = 0;
tty->outputUsesInterrupts = deviceOutputUsesInterrupts;
/*
* Set default parameters
@@ -266,7 +307,6 @@ rtems_termios_close (void *arg)
struct rtems_termios_tty *tty = args->iop->data1;
rtems_status_code sc;
args->ioctl_return = 0;
sc = rtems_semaphore_obtain (ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
@@ -283,8 +323,9 @@ rtems_termios_close (void *arg)
tty->back->forw = tty->forw;
rtems_semaphore_delete (tty->isem);
rtems_semaphore_delete (tty->osem);
rtems_semaphore_delete (tty->rawOutBufSemaphore);
if (tty->read == NULL)
rtems_semaphore_delete (tty->rawBufSemaphore);
rtems_semaphore_delete (tty->rawInBufSemaphore);
free (tty);
}
rtems_semaphore_release (ttyMutex);
@@ -298,6 +339,7 @@ rtems_termios_ioctl (void *arg)
struct rtems_termios_tty *tty = args->iop->data1;
rtems_status_code sc;
args->ioctl_return = 0;
sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
return sc;
@@ -313,30 +355,30 @@ rtems_termios_ioctl (void *arg)
case RTEMS_IO_SET_ATTRIBUTES:
tty->termios = *(struct termios *)args->buffer;
if (tty->termios.c_lflag & ICANON) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
}
else {
rtems_interval ticksPerSecond;
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
tty->vtimeTicks = tty->termios.c_cc[VTIME] * ticksPerSecond / 10;
if (tty->termios.c_cc[VTIME]) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemap`oreTimeout = tty->vtimeTicks;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = tty->vtimeTicks;
if (tty->termios.c_cc[VMIN])
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
else
tty->rawBufSemaphoreFirstTimeout = tty->vtimeTicks;
tty->rawInBufSemaphoreFirstTimeout = tty->vtimeTicks;
}
else {
if (tty->termios.c_cc[VMIN]) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
}
else {
tty->rawBufSemaphoreOptions = RTEMS_NO_WAIT;
tty->rawInBufSemaphoreOptions = RTEMS_NO_WAIT;
}
}
}
@@ -346,6 +388,60 @@ rtems_termios_ioctl (void *arg)
return sc;
}
/*
* Send characters to device-specific code
*/
static void
osend (const char *buf, int len, struct rtems_termios_tty *tty)
{
unsigned int newHead;
rtems_interrupt_level level;
rtems_status_code sc;
if (!tty->outputUsesInterrupts) {
(*tty->write)(tty->minor, buf, len);
return;
}
newHead = tty->rawOutBufHead;
while (len) {
/*
* Performance improvement could be made here.
* Copy multiple bytes to raw buffer:
* if (len > 1) && (space to buffer end, or tail > 1)
* ncopy = MIN (len, space to buffer end or tail)
* memcpy (raw buffer, buf, ncopy)
* buf += ncopy
* len -= ncopy
*
* To minimize latency, the memcpy should be done
* with interrupts enabled.
*/
newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;
rtems_interrupt_disable (level);
while (newHead == tty->rawOutBufTail) {
tty->rawOutBufState = rob_wait;
rtems_interrupt_enable (level);
sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
RTEMS_WAIT,
RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
rtems_interrupt_disable (level);
}
tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
tty->rawOutBufHead = newHead;
if (tty->rawOutBufState == rob_idle) {
rtems_interrupt_enable (level);
tty->rawOutBufState = rob_busy;
(*tty->write)(tty->minor, (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
}
else {
rtems_interrupt_enable (level);
}
len--;
}
}
/*
* Handle output processing
*/
@@ -360,7 +456,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
if (tty->termios.c_oflag & ONLRET)
tty->column = 0;
if (tty->termios.c_oflag & ONLCR) {
(*tty->write)(tty->minor, "\r", 1);
osend ("\r", 1, tty);
tty->column = 0;
}
break;
@@ -381,7 +477,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
i = 8 - (tty->column & 7);
if ((tty->termios.c_oflag & TABDLY) == XTABS) {
tty->column += i;
(*tty->write)(tty->minor, " ", i);
osend ( " ", i, tty);
return;
}
tty->column += i;
@@ -400,7 +496,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
break;
}
}
(*tty->write)(tty->minor, &c, 1);
osend (&c, 1, tty);
}
rtems_status_code
@@ -421,10 +517,8 @@ rtems_termios_write (void *arg)
args->bytes_moved = args->count;
}
else {
if ((*tty->write)(tty->minor, args->buffer, args->count) < 0)
sc = RTEMS_UNSATISFIED;
else
args->bytes_moved = args->count;
osend (args->buffer, args->count, tty);
args->bytes_moved = args->count;
}
rtems_semaphore_release (tty->osem);
return sc;
@@ -441,7 +535,7 @@ echo (unsigned char c, struct rtems_termios_tty *tty)
echobuf[0] = '^';
echobuf[1] = c ^ 0x40;
(*tty->write)(tty->minor, echobuf, 2);
osend (echobuf, 2, tty);
tty->column += 2;
}
else {
@@ -504,18 +598,18 @@ erase (struct rtems_termios_tty *tty, int lineFlag)
* Back up over the tab
*/
while (tty->column > col) {
(*tty->write)(tty->minor, "\b", 1);
osend ("\b", 1, tty);
tty->column--;
}
}
else {
if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
(*tty->write)(tty->minor, "\b \b", 3);
osend ("\b \b", 3, tty);
if (tty->column)
tty->column--;
}
if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
(*tty->write)(tty->minor, "\b \b", 3);
osend ("\b \b", 3, tty);
if (tty->column)
tty->column--;
}
@@ -668,20 +762,20 @@ fillBufferPoll (struct rtems_termios_tty *tty)
static rtems_status_code
fillBufferQueue (struct rtems_termios_tty *tty)
{
rtems_interval timeout = tty->rawBufSemaphoreFirstTimeout;
rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
rtems_status_code sc;
for (;;) {
/*
* Process characters read from raw queue
*/
while (tty->rawBufHead != tty->rawBufTail) {
while (tty->rawInBufHead != tty->rawInBufTail) {
unsigned char c;
unsigned int newHead;
newHead = (tty->rawBufHead + 1) % RAW_BUFFER_SIZE;
c = tty->rawBuf[newHead];
tty->rawBufHead = newHead;
newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
c = tty->rawInBuf[newHead];
tty->rawInBufHead = newHead;
if (tty->termios.c_lflag & ICANON) {
if (siproc (c, tty))
return RTEMS_SUCCESSFUL;
@@ -691,14 +785,14 @@ fillBufferQueue (struct rtems_termios_tty *tty)
if (tty->ccount >= tty->termios.c_cc[VMIN])
return RTEMS_SUCCESSFUL;
}
timeout = tty->rawBufSemaphoreTimeout;
timeout = tty->rawInBufSemaphoreTimeout;
}
/*
* Wait for characters
*/
sc = rtems_semaphore_obtain (tty->rawBufSemaphore,
tty->rawBufSemaphoreOptions,
sc = rtems_semaphore_obtain (tty->rawInBufSemaphore,
tty->rawInBufSemaphoreOptions,
timeout);
if (sc != RTEMS_SUCCESSFUL)
break;
@@ -739,7 +833,8 @@ rtems_termios_read (void *arg)
/*
* Place characters on raw queue.
* NOTE: This routine runs in the context of the device interrupt handler.
* NOTE: This routine runs in the context of the
* device receive interrupt handler.
*/
void
rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
@@ -748,40 +843,52 @@ rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
unsigned int newTail;
while (len) {
newTail = (tty->rawBufTail + 1) % RAW_BUFFER_SIZE;
if (newTail == tty->rawBufHead) {
tty->rawBufDropped += len;
newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
if (newTail == tty->rawInBufHead) {
tty->rawInBufDropped += len;
break;
}
tty->rawBuf[newTail] = *buf++;
tty->rawInBuf[newTail] = *buf++;
len--;
tty->rawBufTail = newTail;
tty->rawInBufTail = newTail;
}
rtems_semaphore_release (tty->rawBufSemaphore);
rtems_semaphore_release (tty->rawInBufSemaphore);
}
/*
* Reserve enough resources to open every physical device once.
* Characters have been transmitted
* NOTE: This routine runs in the context of the
* device transmit interrupt handler.
* The second argument is the number of characters transmitted so far.
* This value will always be 1 for devices which generate an interrupt
* for each transmitted character.
*/
void rtems_termios_reserve_resources(
rtems_configuration_table *configuration,
rtems_unsigned32 number_of_devices
)
void
rtems_termios_dequeue_characters (void *ttyp, int len)
{
static int first_time = 1;
rtems_api_configuration_table *rtems_config;
struct rtems_termios_tty *tty = ttyp;
unsigned int newTail;
int nToSend;
if (!configuration)
rtems_fatal_error_occurred (0xFFF0F001);
rtems_config = configuration->RTEMS_api_configuration;
if (!rtems_config)
rtems_fatal_error_occurred (0xFFF0F002);
if (first_time)
rtems_config->maximum_semaphores += 1;
first_time = 0;
rtems_config->maximum_semaphores += (3 * number_of_devices);
if (tty->rawOutBufState == rob_wait)
rtems_semaphore_release (tty->rawOutBufSemaphore);
newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
if (newTail == tty->rawOutBufHead) {
/*
* Buffer empty
*/
tty->rawOutBufState = rob_idle;
}
else {
/*
* 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->write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
}
tty->rawOutBufTail = newTail;
}

View File

@@ -139,7 +139,8 @@ rtems_status_code rtems_termios_open (
int (*deviceFirstOpen)(int major, int minor, void *arg),
int (*deviceLastClose)(int major, int minor, void *arg),
int (*deviceRead)(int minor),
int (*deviceWrite)(int minor, char *buf, int len)
int (*deviceWrite)(int minor, char *buf, int len),
int deviceOutputUsesInterrupts
);
rtems_status_code rtems_termios_close (void *arg);

View File

@@ -40,7 +40,7 @@ static void *smc1ttyp;
/*
* I/O buffers and pointers to buffer descriptors
*/
static volatile char rxBuf[RXBUFSIZE], txBuf;
static volatile char rxBuf[RXBUFSIZE];
static volatile m360BufferDescriptor_t *smcRxBd, *smcTxBd;
/*
@@ -62,6 +62,15 @@ smc1InterruptHandler (rtems_vector_number v)
smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
}
}
/*
* Buffer transmitted?
*/
if (m360.smc1.smce & 0x2) {
m360.smc1.smce = 0x2;
if ((smcTxBd->status & M360_BD_READY) == 0)
rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
}
m360.cisr = 1UL << 4; /* Clear SMC1 interrupt-in-service bit */
}
@@ -122,8 +131,6 @@ smc1Initialize (void)
* Setup the Transmit Buffer Descriptor
*/
smcTxBd->status = M360_BD_WRAP;
smcTxBd->length = 1;
smcTxBd->buffer = &txBuf;
/*
* Set up SMC1 general and protocol-specific mode registers
@@ -150,7 +157,7 @@ smc1Initialize (void)
sc = rtems_interrupt_catch (smc1InterruptHandler,
(m360.cicr & 0xE0) | 0x04,
&old_handler);
m360.smc1.smcm = 1; /* Enable SMC1 receiver interrupt */
m360.smc1.smcm = 3; /* Enable SMC1 TX and RX interrupts */
m360.cimr |= 1UL << 4; /* Enable SMC1 interrupts */
}
#endif
@@ -168,19 +175,32 @@ smc1Read (int minor)
return c;
}
/*
* Device-dependent write routine
* Interrupt-driven devices:
* Begin transmission of as many characters as possible (minimum is 1).
* Polling devices:
* Transmit all characters.
*/
static int
smc1Write (int minor, char *buf, int len)
{
int nwrite = 0;
while (nwrite < len) {
#if (defined (M360_SMC1_INTERRUPT))
smcTxBd->buffer = buf;
smcTxBd->length = len;
smcTxBd->status = M360_BD_READY | M360_BD_WRAP | M360_BD_INTERRUPT;
#else
while (len--) {
static char txBuf;
while (smcTxBd->status & M360_BD_READY)
continue;
txBuf = *buf++;
smcTxBd->buffer = &txBuf;
smcTxBd->length = 1;
smcTxBd->status = M360_BD_READY | M360_BD_WRAP;
nwrite++;
}
return nwrite;
#endif
return 0;
}
/*
@@ -189,6 +209,16 @@ smc1Write (int minor, char *buf, int len)
***************
*/
/*
* Reserve resources consumed by this driver
*/
void console_reserve_resources(
rtems_configuration_table *configuration
)
{
rtems_termios_reserve_resources (configuration, 1);
}
/*
* Initialize and register the device
*/
@@ -237,14 +267,16 @@ rtems_device_driver console_open(
NULL,
NULL,
NULL,
smc1Write);
smc1Write,
1);
smc1ttyp = args->iop->data1;
#else
sc = rtems_termios_open (major, minor, arg,
NULL,
NULL,
smc1Read,
smc1Write);
smc1Write,
0);
#endif
return sc;
}

View File

@@ -139,7 +139,8 @@ rtems_status_code rtems_termios_open (
int (*deviceFirstOpen)(int major, int minor, void *arg),
int (*deviceLastClose)(int major, int minor, void *arg),
int (*deviceRead)(int minor),
int (*deviceWrite)(int minor, char *buf, int len)
int (*deviceWrite)(int minor, char *buf, int len),
int deviceOutputUsesInterrupts
);
rtems_status_code rtems_termios_close (void *arg);

View File

@@ -1,20 +1,13 @@
/*
* TERMIOS serial line support
*
* Authors:
* Author:
* W. Eric Norum
* Saskatchewan Accelerator Laboratory
* University of Saskatchewan
* Saskatoon, Saskatchewan, CANADA
* eric@skatter.usask.ca
*
* AND
*
* Katsutoshi Shibuya
* BU Denken Co.,Ltd.
* Sapporo, JAPAN
* shibuya@mxb.meshnet.or.jp
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
@@ -37,9 +30,12 @@
#define CBUFSIZE 256
/*
* The size of the raw input message queue
* The sizes of the raw message buffers.
* On most architectures it is quite a bit more
* efficient if these are powers of two.
*/
#define RAW_BUFFER_SIZE 128
#define RAW_INPUT_BUFFER_SIZE 128
#define RAW_OUTPUT_BUFFER_SIZE 64
/*
* Variables associated with each termios instance.
@@ -89,16 +85,26 @@ struct rtems_termios_tty {
rtems_interval vtimeTicks;
/*
* Raw character buffer
* Raw input character buffer
*/
volatile char rawBuf[RAW_BUFFER_SIZE];
volatile unsigned int rawBufHead;
volatile unsigned int rawBufTail;
rtems_id rawBufSemaphore;
rtems_unsigned32 rawBufSemaphoreOptions;
rtems_interval rawBufSemaphoreTimeout;
rtems_interval rawBufSemaphoreFirstTimeout;
unsigned int rawBufDropped; /* Statistics */
volatile char rawInBuf[RAW_INPUT_BUFFER_SIZE];
volatile unsigned int rawInBufHead;
volatile unsigned int rawInBufTail;
rtems_id rawInBufSemaphore;
rtems_unsigned32 rawInBufSemaphoreOptions;
rtems_interval rawInBufSemaphoreTimeout;
rtems_interval rawInBufSemaphoreFirstTimeout;
unsigned int rawInBufDropped; /* Statistics */
/*
* Raw output character buffer
*/
char outputUsesInterrupts;
volatile char rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];
volatile unsigned int rawOutBufHead;
volatile unsigned int rawOutBufTail;
rtems_id rawOutBufSemaphore;
enum {rob_idle, rob_busy, rob_wait } rawOutBufState;
/*
* Callbacks to device-specific routines
@@ -110,6 +116,29 @@ struct rtems_termios_tty {
static struct rtems_termios_tty *ttyHead, *ttyTail;
static rtems_id ttyMutex;
/*
* Reserve enough resources to open every physical device once.
*/
void
rtems_termios_reserve_resources (
rtems_configuration_table *configuration,
rtems_unsigned32 number_of_devices
)
{
static int first_time = 1;
rtems_api_configuration_table *rtems_config;
if (!configuration)
rtems_fatal_error_occurred (0xFFF0F001);
rtems_config = configuration->RTEMS_api_configuration;
if (!rtems_config)
rtems_fatal_error_occurred (0xFFF0F002);
if (first_time)
rtems_config->maximum_semaphores += 1;
first_time = 0;
rtems_config->maximum_semaphores += (4 * number_of_devices);
}
void
rtems_termios_initialize (void)
{
@@ -141,7 +170,8 @@ rtems_termios_open (
int (*deviceFirstOpen)(int major, int minor, void *arg),
int (*deviceLastClose)(int major, int minor, void *arg),
int (*deviceRead)(int minor),
int (*deviceWrite)(int minor, char *buf, int len)
int (*deviceWrite)(int minor, char *buf, int len),
int deviceOutputUsesInterrupts
)
{
rtems_status_code sc;
@@ -194,6 +224,16 @@ rtems_termios_open (
&tty->osem);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
sc = rtems_semaphore_create (
rtems_build_name ('T', 'R', 'x', c),
0,
RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
RTEMS_NO_PRIORITY,
&tty->rawOutBufSemaphore);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
tty->rawOutBufHead = 0;
tty->rawOutBufTail = 0;
/*
* Set callbacks
@@ -206,11 +246,11 @@ rtems_termios_open (
0,
RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
RTEMS_NO_PRIORITY,
&tty->rawBufSemaphore);
&tty->rawInBufSemaphore);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
tty->rawBufHead = 0;
tty->rawBufTail = 0;
tty->rawInBufHead = 0;
tty->rawInBufTail = 0;
}
/*
@@ -218,6 +258,7 @@ rtems_termios_open (
*/
tty->column = 0;
tty->cindex = tty->ccount = 0;
tty->outputUsesInterrupts = deviceOutputUsesInterrupts;
/*
* Set default parameters
@@ -266,7 +307,6 @@ rtems_termios_close (void *arg)
struct rtems_termios_tty *tty = args->iop->data1;
rtems_status_code sc;
args->ioctl_return = 0;
sc = rtems_semaphore_obtain (ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
@@ -283,8 +323,9 @@ rtems_termios_close (void *arg)
tty->back->forw = tty->forw;
rtems_semaphore_delete (tty->isem);
rtems_semaphore_delete (tty->osem);
rtems_semaphore_delete (tty->rawOutBufSemaphore);
if (tty->read == NULL)
rtems_semaphore_delete (tty->rawBufSemaphore);
rtems_semaphore_delete (tty->rawInBufSemaphore);
free (tty);
}
rtems_semaphore_release (ttyMutex);
@@ -298,6 +339,7 @@ rtems_termios_ioctl (void *arg)
struct rtems_termios_tty *tty = args->iop->data1;
rtems_status_code sc;
args->ioctl_return = 0;
sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
return sc;
@@ -313,30 +355,30 @@ rtems_termios_ioctl (void *arg)
case RTEMS_IO_SET_ATTRIBUTES:
tty->termios = *(struct termios *)args->buffer;
if (tty->termios.c_lflag & ICANON) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
}
else {
rtems_interval ticksPerSecond;
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
tty->vtimeTicks = tty->termios.c_cc[VTIME] * ticksPerSecond / 10;
if (tty->termios.c_cc[VTIME]) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemap`oreTimeout = tty->vtimeTicks;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = tty->vtimeTicks;
if (tty->termios.c_cc[VMIN])
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
else
tty->rawBufSemaphoreFirstTimeout = tty->vtimeTicks;
tty->rawInBufSemaphoreFirstTimeout = tty->vtimeTicks;
}
else {
if (tty->termios.c_cc[VMIN]) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
}
else {
tty->rawBufSemaphoreOptions = RTEMS_NO_WAIT;
tty->rawInBufSemaphoreOptions = RTEMS_NO_WAIT;
}
}
}
@@ -346,6 +388,60 @@ rtems_termios_ioctl (void *arg)
return sc;
}
/*
* Send characters to device-specific code
*/
static void
osend (const char *buf, int len, struct rtems_termios_tty *tty)
{
unsigned int newHead;
rtems_interrupt_level level;
rtems_status_code sc;
if (!tty->outputUsesInterrupts) {
(*tty->write)(tty->minor, buf, len);
return;
}
newHead = tty->rawOutBufHead;
while (len) {
/*
* Performance improvement could be made here.
* Copy multiple bytes to raw buffer:
* if (len > 1) && (space to buffer end, or tail > 1)
* ncopy = MIN (len, space to buffer end or tail)
* memcpy (raw buffer, buf, ncopy)
* buf += ncopy
* len -= ncopy
*
* To minimize latency, the memcpy should be done
* with interrupts enabled.
*/
newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;
rtems_interrupt_disable (level);
while (newHead == tty->rawOutBufTail) {
tty->rawOutBufState = rob_wait;
rtems_interrupt_enable (level);
sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
RTEMS_WAIT,
RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
rtems_interrupt_disable (level);
}
tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
tty->rawOutBufHead = newHead;
if (tty->rawOutBufState == rob_idle) {
rtems_interrupt_enable (level);
tty->rawOutBufState = rob_busy;
(*tty->write)(tty->minor, (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
}
else {
rtems_interrupt_enable (level);
}
len--;
}
}
/*
* Handle output processing
*/
@@ -360,7 +456,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
if (tty->termios.c_oflag & ONLRET)
tty->column = 0;
if (tty->termios.c_oflag & ONLCR) {
(*tty->write)(tty->minor, "\r", 1);
osend ("\r", 1, tty);
tty->column = 0;
}
break;
@@ -381,7 +477,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
i = 8 - (tty->column & 7);
if ((tty->termios.c_oflag & TABDLY) == XTABS) {
tty->column += i;
(*tty->write)(tty->minor, " ", i);
osend ( " ", i, tty);
return;
}
tty->column += i;
@@ -400,7 +496,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
break;
}
}
(*tty->write)(tty->minor, &c, 1);
osend (&c, 1, tty);
}
rtems_status_code
@@ -421,10 +517,8 @@ rtems_termios_write (void *arg)
args->bytes_moved = args->count;
}
else {
if ((*tty->write)(tty->minor, args->buffer, args->count) < 0)
sc = RTEMS_UNSATISFIED;
else
args->bytes_moved = args->count;
osend (args->buffer, args->count, tty);
args->bytes_moved = args->count;
}
rtems_semaphore_release (tty->osem);
return sc;
@@ -441,7 +535,7 @@ echo (unsigned char c, struct rtems_termios_tty *tty)
echobuf[0] = '^';
echobuf[1] = c ^ 0x40;
(*tty->write)(tty->minor, echobuf, 2);
osend (echobuf, 2, tty);
tty->column += 2;
}
else {
@@ -504,18 +598,18 @@ erase (struct rtems_termios_tty *tty, int lineFlag)
* Back up over the tab
*/
while (tty->column > col) {
(*tty->write)(tty->minor, "\b", 1);
osend ("\b", 1, tty);
tty->column--;
}
}
else {
if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
(*tty->write)(tty->minor, "\b \b", 3);
osend ("\b \b", 3, tty);
if (tty->column)
tty->column--;
}
if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
(*tty->write)(tty->minor, "\b \b", 3);
osend ("\b \b", 3, tty);
if (tty->column)
tty->column--;
}
@@ -668,20 +762,20 @@ fillBufferPoll (struct rtems_termios_tty *tty)
static rtems_status_code
fillBufferQueue (struct rtems_termios_tty *tty)
{
rtems_interval timeout = tty->rawBufSemaphoreFirstTimeout;
rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
rtems_status_code sc;
for (;;) {
/*
* Process characters read from raw queue
*/
while (tty->rawBufHead != tty->rawBufTail) {
while (tty->rawInBufHead != tty->rawInBufTail) {
unsigned char c;
unsigned int newHead;
newHead = (tty->rawBufHead + 1) % RAW_BUFFER_SIZE;
c = tty->rawBuf[newHead];
tty->rawBufHead = newHead;
newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
c = tty->rawInBuf[newHead];
tty->rawInBufHead = newHead;
if (tty->termios.c_lflag & ICANON) {
if (siproc (c, tty))
return RTEMS_SUCCESSFUL;
@@ -691,14 +785,14 @@ fillBufferQueue (struct rtems_termios_tty *tty)
if (tty->ccount >= tty->termios.c_cc[VMIN])
return RTEMS_SUCCESSFUL;
}
timeout = tty->rawBufSemaphoreTimeout;
timeout = tty->rawInBufSemaphoreTimeout;
}
/*
* Wait for characters
*/
sc = rtems_semaphore_obtain (tty->rawBufSemaphore,
tty->rawBufSemaphoreOptions,
sc = rtems_semaphore_obtain (tty->rawInBufSemaphore,
tty->rawInBufSemaphoreOptions,
timeout);
if (sc != RTEMS_SUCCESSFUL)
break;
@@ -739,7 +833,8 @@ rtems_termios_read (void *arg)
/*
* Place characters on raw queue.
* NOTE: This routine runs in the context of the device interrupt handler.
* NOTE: This routine runs in the context of the
* device receive interrupt handler.
*/
void
rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
@@ -748,40 +843,52 @@ rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
unsigned int newTail;
while (len) {
newTail = (tty->rawBufTail + 1) % RAW_BUFFER_SIZE;
if (newTail == tty->rawBufHead) {
tty->rawBufDropped += len;
newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
if (newTail == tty->rawInBufHead) {
tty->rawInBufDropped += len;
break;
}
tty->rawBuf[newTail] = *buf++;
tty->rawInBuf[newTail] = *buf++;
len--;
tty->rawBufTail = newTail;
tty->rawInBufTail = newTail;
}
rtems_semaphore_release (tty->rawBufSemaphore);
rtems_semaphore_release (tty->rawInBufSemaphore);
}
/*
* Reserve enough resources to open every physical device once.
* Characters have been transmitted
* NOTE: This routine runs in the context of the
* device transmit interrupt handler.
* The second argument is the number of characters transmitted so far.
* This value will always be 1 for devices which generate an interrupt
* for each transmitted character.
*/
void rtems_termios_reserve_resources(
rtems_configuration_table *configuration,
rtems_unsigned32 number_of_devices
)
void
rtems_termios_dequeue_characters (void *ttyp, int len)
{
static int first_time = 1;
rtems_api_configuration_table *rtems_config;
struct rtems_termios_tty *tty = ttyp;
unsigned int newTail;
int nToSend;
if (!configuration)
rtems_fatal_error_occurred (0xFFF0F001);
rtems_config = configuration->RTEMS_api_configuration;
if (!rtems_config)
rtems_fatal_error_occurred (0xFFF0F002);
if (first_time)
rtems_config->maximum_semaphores += 1;
first_time = 0;
rtems_config->maximum_semaphores += (3 * number_of_devices);
if (tty->rawOutBufState == rob_wait)
rtems_semaphore_release (tty->rawOutBufSemaphore);
newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
if (newTail == tty->rawOutBufHead) {
/*
* Buffer empty
*/
tty->rawOutBufState = rob_idle;
}
else {
/*
* 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->write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
}
tty->rawOutBufTail = newTail;
}

View File

@@ -139,7 +139,8 @@ rtems_status_code rtems_termios_open (
int (*deviceFirstOpen)(int major, int minor, void *arg),
int (*deviceLastClose)(int major, int minor, void *arg),
int (*deviceRead)(int minor),
int (*deviceWrite)(int minor, char *buf, int len)
int (*deviceWrite)(int minor, char *buf, int len),
int deviceOutputUsesInterrupts
);
rtems_status_code rtems_termios_close (void *arg);

View File

@@ -1,20 +1,13 @@
/*
* TERMIOS serial line support
*
* Authors:
* Author:
* W. Eric Norum
* Saskatchewan Accelerator Laboratory
* University of Saskatchewan
* Saskatoon, Saskatchewan, CANADA
* eric@skatter.usask.ca
*
* AND
*
* Katsutoshi Shibuya
* BU Denken Co.,Ltd.
* Sapporo, JAPAN
* shibuya@mxb.meshnet.or.jp
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
@@ -37,9 +30,12 @@
#define CBUFSIZE 256
/*
* The size of the raw input message queue
* The sizes of the raw message buffers.
* On most architectures it is quite a bit more
* efficient if these are powers of two.
*/
#define RAW_BUFFER_SIZE 128
#define RAW_INPUT_BUFFER_SIZE 128
#define RAW_OUTPUT_BUFFER_SIZE 64
/*
* Variables associated with each termios instance.
@@ -89,16 +85,26 @@ struct rtems_termios_tty {
rtems_interval vtimeTicks;
/*
* Raw character buffer
* Raw input character buffer
*/
volatile char rawBuf[RAW_BUFFER_SIZE];
volatile unsigned int rawBufHead;
volatile unsigned int rawBufTail;
rtems_id rawBufSemaphore;
rtems_unsigned32 rawBufSemaphoreOptions;
rtems_interval rawBufSemaphoreTimeout;
rtems_interval rawBufSemaphoreFirstTimeout;
unsigned int rawBufDropped; /* Statistics */
volatile char rawInBuf[RAW_INPUT_BUFFER_SIZE];
volatile unsigned int rawInBufHead;
volatile unsigned int rawInBufTail;
rtems_id rawInBufSemaphore;
rtems_unsigned32 rawInBufSemaphoreOptions;
rtems_interval rawInBufSemaphoreTimeout;
rtems_interval rawInBufSemaphoreFirstTimeout;
unsigned int rawInBufDropped; /* Statistics */
/*
* Raw output character buffer
*/
char outputUsesInterrupts;
volatile char rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];
volatile unsigned int rawOutBufHead;
volatile unsigned int rawOutBufTail;
rtems_id rawOutBufSemaphore;
enum {rob_idle, rob_busy, rob_wait } rawOutBufState;
/*
* Callbacks to device-specific routines
@@ -110,6 +116,29 @@ struct rtems_termios_tty {
static struct rtems_termios_tty *ttyHead, *ttyTail;
static rtems_id ttyMutex;
/*
* Reserve enough resources to open every physical device once.
*/
void
rtems_termios_reserve_resources (
rtems_configuration_table *configuration,
rtems_unsigned32 number_of_devices
)
{
static int first_time = 1;
rtems_api_configuration_table *rtems_config;
if (!configuration)
rtems_fatal_error_occurred (0xFFF0F001);
rtems_config = configuration->RTEMS_api_configuration;
if (!rtems_config)
rtems_fatal_error_occurred (0xFFF0F002);
if (first_time)
rtems_config->maximum_semaphores += 1;
first_time = 0;
rtems_config->maximum_semaphores += (4 * number_of_devices);
}
void
rtems_termios_initialize (void)
{
@@ -141,7 +170,8 @@ rtems_termios_open (
int (*deviceFirstOpen)(int major, int minor, void *arg),
int (*deviceLastClose)(int major, int minor, void *arg),
int (*deviceRead)(int minor),
int (*deviceWrite)(int minor, char *buf, int len)
int (*deviceWrite)(int minor, char *buf, int len),
int deviceOutputUsesInterrupts
)
{
rtems_status_code sc;
@@ -194,6 +224,16 @@ rtems_termios_open (
&tty->osem);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
sc = rtems_semaphore_create (
rtems_build_name ('T', 'R', 'x', c),
0,
RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
RTEMS_NO_PRIORITY,
&tty->rawOutBufSemaphore);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
tty->rawOutBufHead = 0;
tty->rawOutBufTail = 0;
/*
* Set callbacks
@@ -206,11 +246,11 @@ rtems_termios_open (
0,
RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
RTEMS_NO_PRIORITY,
&tty->rawBufSemaphore);
&tty->rawInBufSemaphore);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
tty->rawBufHead = 0;
tty->rawBufTail = 0;
tty->rawInBufHead = 0;
tty->rawInBufTail = 0;
}
/*
@@ -218,6 +258,7 @@ rtems_termios_open (
*/
tty->column = 0;
tty->cindex = tty->ccount = 0;
tty->outputUsesInterrupts = deviceOutputUsesInterrupts;
/*
* Set default parameters
@@ -266,7 +307,6 @@ rtems_termios_close (void *arg)
struct rtems_termios_tty *tty = args->iop->data1;
rtems_status_code sc;
args->ioctl_return = 0;
sc = rtems_semaphore_obtain (ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
@@ -283,8 +323,9 @@ rtems_termios_close (void *arg)
tty->back->forw = tty->forw;
rtems_semaphore_delete (tty->isem);
rtems_semaphore_delete (tty->osem);
rtems_semaphore_delete (tty->rawOutBufSemaphore);
if (tty->read == NULL)
rtems_semaphore_delete (tty->rawBufSemaphore);
rtems_semaphore_delete (tty->rawInBufSemaphore);
free (tty);
}
rtems_semaphore_release (ttyMutex);
@@ -298,6 +339,7 @@ rtems_termios_ioctl (void *arg)
struct rtems_termios_tty *tty = args->iop->data1;
rtems_status_code sc;
args->ioctl_return = 0;
sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
return sc;
@@ -313,30 +355,30 @@ rtems_termios_ioctl (void *arg)
case RTEMS_IO_SET_ATTRIBUTES:
tty->termios = *(struct termios *)args->buffer;
if (tty->termios.c_lflag & ICANON) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
}
else {
rtems_interval ticksPerSecond;
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
tty->vtimeTicks = tty->termios.c_cc[VTIME] * ticksPerSecond / 10;
if (tty->termios.c_cc[VTIME]) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemap`oreTimeout = tty->vtimeTicks;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = tty->vtimeTicks;
if (tty->termios.c_cc[VMIN])
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
else
tty->rawBufSemaphoreFirstTimeout = tty->vtimeTicks;
tty->rawInBufSemaphoreFirstTimeout = tty->vtimeTicks;
}
else {
if (tty->termios.c_cc[VMIN]) {
tty->rawBufSemaphoreOptions = RTEMS_WAIT;
tty->rawBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
}
else {
tty->rawBufSemaphoreOptions = RTEMS_NO_WAIT;
tty->rawInBufSemaphoreOptions = RTEMS_NO_WAIT;
}
}
}
@@ -346,6 +388,60 @@ rtems_termios_ioctl (void *arg)
return sc;
}
/*
* Send characters to device-specific code
*/
static void
osend (const char *buf, int len, struct rtems_termios_tty *tty)
{
unsigned int newHead;
rtems_interrupt_level level;
rtems_status_code sc;
if (!tty->outputUsesInterrupts) {
(*tty->write)(tty->minor, buf, len);
return;
}
newHead = tty->rawOutBufHead;
while (len) {
/*
* Performance improvement could be made here.
* Copy multiple bytes to raw buffer:
* if (len > 1) && (space to buffer end, or tail > 1)
* ncopy = MIN (len, space to buffer end or tail)
* memcpy (raw buffer, buf, ncopy)
* buf += ncopy
* len -= ncopy
*
* To minimize latency, the memcpy should be done
* with interrupts enabled.
*/
newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;
rtems_interrupt_disable (level);
while (newHead == tty->rawOutBufTail) {
tty->rawOutBufState = rob_wait;
rtems_interrupt_enable (level);
sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
RTEMS_WAIT,
RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
rtems_interrupt_disable (level);
}
tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
tty->rawOutBufHead = newHead;
if (tty->rawOutBufState == rob_idle) {
rtems_interrupt_enable (level);
tty->rawOutBufState = rob_busy;
(*tty->write)(tty->minor, (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
}
else {
rtems_interrupt_enable (level);
}
len--;
}
}
/*
* Handle output processing
*/
@@ -360,7 +456,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
if (tty->termios.c_oflag & ONLRET)
tty->column = 0;
if (tty->termios.c_oflag & ONLCR) {
(*tty->write)(tty->minor, "\r", 1);
osend ("\r", 1, tty);
tty->column = 0;
}
break;
@@ -381,7 +477,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
i = 8 - (tty->column & 7);
if ((tty->termios.c_oflag & TABDLY) == XTABS) {
tty->column += i;
(*tty->write)(tty->minor, " ", i);
osend ( " ", i, tty);
return;
}
tty->column += i;
@@ -400,7 +496,7 @@ oproc (unsigned char c, struct rtems_termios_tty *tty)
break;
}
}
(*tty->write)(tty->minor, &c, 1);
osend (&c, 1, tty);
}
rtems_status_code
@@ -421,10 +517,8 @@ rtems_termios_write (void *arg)
args->bytes_moved = args->count;
}
else {
if ((*tty->write)(tty->minor, args->buffer, args->count) < 0)
sc = RTEMS_UNSATISFIED;
else
args->bytes_moved = args->count;
osend (args->buffer, args->count, tty);
args->bytes_moved = args->count;
}
rtems_semaphore_release (tty->osem);
return sc;
@@ -441,7 +535,7 @@ echo (unsigned char c, struct rtems_termios_tty *tty)
echobuf[0] = '^';
echobuf[1] = c ^ 0x40;
(*tty->write)(tty->minor, echobuf, 2);
osend (echobuf, 2, tty);
tty->column += 2;
}
else {
@@ -504,18 +598,18 @@ erase (struct rtems_termios_tty *tty, int lineFlag)
* Back up over the tab
*/
while (tty->column > col) {
(*tty->write)(tty->minor, "\b", 1);
osend ("\b", 1, tty);
tty->column--;
}
}
else {
if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
(*tty->write)(tty->minor, "\b \b", 3);
osend ("\b \b", 3, tty);
if (tty->column)
tty->column--;
}
if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
(*tty->write)(tty->minor, "\b \b", 3);
osend ("\b \b", 3, tty);
if (tty->column)
tty->column--;
}
@@ -668,20 +762,20 @@ fillBufferPoll (struct rtems_termios_tty *tty)
static rtems_status_code
fillBufferQueue (struct rtems_termios_tty *tty)
{
rtems_interval timeout = tty->rawBufSemaphoreFirstTimeout;
rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
rtems_status_code sc;
for (;;) {
/*
* Process characters read from raw queue
*/
while (tty->rawBufHead != tty->rawBufTail) {
while (tty->rawInBufHead != tty->rawInBufTail) {
unsigned char c;
unsigned int newHead;
newHead = (tty->rawBufHead + 1) % RAW_BUFFER_SIZE;
c = tty->rawBuf[newHead];
tty->rawBufHead = newHead;
newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
c = tty->rawInBuf[newHead];
tty->rawInBufHead = newHead;
if (tty->termios.c_lflag & ICANON) {
if (siproc (c, tty))
return RTEMS_SUCCESSFUL;
@@ -691,14 +785,14 @@ fillBufferQueue (struct rtems_termios_tty *tty)
if (tty->ccount >= tty->termios.c_cc[VMIN])
return RTEMS_SUCCESSFUL;
}
timeout = tty->rawBufSemaphoreTimeout;
timeout = tty->rawInBufSemaphoreTimeout;
}
/*
* Wait for characters
*/
sc = rtems_semaphore_obtain (tty->rawBufSemaphore,
tty->rawBufSemaphoreOptions,
sc = rtems_semaphore_obtain (tty->rawInBufSemaphore,
tty->rawInBufSemaphoreOptions,
timeout);
if (sc != RTEMS_SUCCESSFUL)
break;
@@ -739,7 +833,8 @@ rtems_termios_read (void *arg)
/*
* Place characters on raw queue.
* NOTE: This routine runs in the context of the device interrupt handler.
* NOTE: This routine runs in the context of the
* device receive interrupt handler.
*/
void
rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
@@ -748,40 +843,52 @@ rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
unsigned int newTail;
while (len) {
newTail = (tty->rawBufTail + 1) % RAW_BUFFER_SIZE;
if (newTail == tty->rawBufHead) {
tty->rawBufDropped += len;
newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
if (newTail == tty->rawInBufHead) {
tty->rawInBufDropped += len;
break;
}
tty->rawBuf[newTail] = *buf++;
tty->rawInBuf[newTail] = *buf++;
len--;
tty->rawBufTail = newTail;
tty->rawInBufTail = newTail;
}
rtems_semaphore_release (tty->rawBufSemaphore);
rtems_semaphore_release (tty->rawInBufSemaphore);
}
/*
* Reserve enough resources to open every physical device once.
* Characters have been transmitted
* NOTE: This routine runs in the context of the
* device transmit interrupt handler.
* The second argument is the number of characters transmitted so far.
* This value will always be 1 for devices which generate an interrupt
* for each transmitted character.
*/
void rtems_termios_reserve_resources(
rtems_configuration_table *configuration,
rtems_unsigned32 number_of_devices
)
void
rtems_termios_dequeue_characters (void *ttyp, int len)
{
static int first_time = 1;
rtems_api_configuration_table *rtems_config;
struct rtems_termios_tty *tty = ttyp;
unsigned int newTail;
int nToSend;
if (!configuration)
rtems_fatal_error_occurred (0xFFF0F001);
rtems_config = configuration->RTEMS_api_configuration;
if (!rtems_config)
rtems_fatal_error_occurred (0xFFF0F002);
if (first_time)
rtems_config->maximum_semaphores += 1;
first_time = 0;
rtems_config->maximum_semaphores += (3 * number_of_devices);
if (tty->rawOutBufState == rob_wait)
rtems_semaphore_release (tty->rawOutBufSemaphore);
newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
if (newTail == tty->rawOutBufHead) {
/*
* Buffer empty
*/
tty->rawOutBufState = rob_idle;
}
else {
/*
* 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->write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
}
tty->rawOutBufTail = newTail;
}