diff options
author | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-04-18 17:08:27 +0000 |
---|---|---|
committer | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-04-18 17:08:27 +0000 |
commit | 530040b164b352fcee157f317b2ac7e1609d5956 (patch) | |
tree | 19315fef4996c7f98e75525ffa73ee284eb5c7de /nuttx/drivers/serial | |
parent | 6aa752b3380cebd42e1870e8c8f85d02f8956465 (diff) | |
download | px4-firmware-530040b164b352fcee157f317b2ac7e1609d5956.tar.gz px4-firmware-530040b164b352fcee157f317b2ac7e1609d5956.tar.bz2 px4-firmware-530040b164b352fcee157f317b2ac7e1609d5956.zip |
drivers/serial: Don't disable Rx interrrupts on each character
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4631 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx/drivers/serial')
-rw-r--r-- | nuttx/drivers/serial/serial.c | 75 |
1 files changed, 56 insertions, 19 deletions
diff --git a/nuttx/drivers/serial/serial.c b/nuttx/drivers/serial/serial.c index 7aa342d9d..c43060b2b 100644 --- a/nuttx/drivers/serial/serial.c +++ b/nuttx/drivers/serial/serial.c @@ -311,6 +311,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen FAR uart_dev_t *dev = inode->i_private; irqstate_t flags; ssize_t recvd = 0; + int16_t tail; /* Only one user can be accessing dev->recv.tail at once */ @@ -323,19 +324,31 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen while (recvd < buflen) { - /* Check if there is more data to return in the circular buffer */ + /* Check if there is more data to return in the circular buffer. + * NOTE: Rx interrupt handling logic may aynchronously increment + * the head index but must not modify the tail index. The tail + * index is only modified in this function. Therefore, no + * special handshaking is required here. + */ - uart_disablerxint(dev); - if (dev->recv.head != dev->recv.tail) + tail = dev->recv.tail; + if (dev->recv.head != tail) { - *buffer++ = dev->recv.buffer[dev->recv.tail]; + /* Take the next character from the tail of the buffer */ + + *buffer++ = dev->recv.buffer[tail]; recvd++; - if (++(dev->recv.tail) >= dev->recv.size) + /* Increment the tail index. Most operations are done using the + * local variable 'tail' so that the final dev->recv.tail update + * is atomic. + */ + + if (++tail >= dev->recv.size) { - dev->recv.tail = 0; + tail = 0; } - uart_enablerxint(dev); + dev->recv.tail = tail; } #ifdef CONFIG_DEV_SERIAL_FULLBLOCKS @@ -354,8 +367,6 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen { recvd = -EAGAIN; } - - uart_enablerxint(dev); break; } #else @@ -369,7 +380,6 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen * received up to the wait condition. */ - uart_enablerxint(dev); break; } @@ -383,7 +393,6 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen /* Break out of the loop returning -EAGAIN */ recvd = -EAGAIN; - uart_enablerxint(dev); break; } #endif @@ -391,16 +400,44 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen else { - /* Wait for some characters to be sent from the buffer with the RX interrupt - * re-enabled. Interrupts are disabled briefly to assure that the following - * operations are atomic. + /* Disable Rx interrupts and test again... */ + + uart_disablerxint(dev); + + /* If the Rx ring buffer still empty? Bytes may have been addded + * between the last time that we checked and when we disabled Rx + * interrupts. */ - flags = irqsave(); - dev->recvwaiting = true; - uart_enablerxint(dev); - uart_takesem(&dev->recvsem); - irqrestore(flags); + if (dev->recv.head == dev->recv.tail) + { + /* Yes.. the buffer is still empty. Wait for some characters + * to be received into the buffer with the RX interrupt re- + * enabled. All interrupts are disabled briefly to assure + * that the following operations are atomic. + */ + + flags = irqsave(); + dev->recvwaiting = true; + uart_enablerxint(dev); + + /* Now wait with the Rx interrupt re-enabled. NuttX will + * automatically re-enable global interrupts when this + * thread goes to sleep. + */ + + uart_takesem(&dev->recvsem); + irqrestore(flags); + } + else + { + /* No... the ring buffer is no longer empty. Just re-enable Rx + * interrupts and accept the new data on the next time through + * the loop. + */ + + uart_enablerxint(dev); + } } } |