From af447e106c50246185a2b666900022043636d418 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 10 Mar 2007 00:17:29 +0000 Subject: Fix IRQ-related bugs, fix serial read logic, add fgets git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@51 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/ChangeLog | 13 ++ nuttx/arch/c5471/src/up_blocktask.c | 2 - nuttx/arch/c5471/src/up_doirq.c | 16 +- nuttx/arch/c5471/src/up_serial.c | 51 +++++- nuttx/include/ctype.h | 50 ++++-- nuttx/include/stdio.h | 1 + nuttx/lib/Makefile | 4 +- nuttx/lib/lib_fgets.c | 306 ++++++++++++++++++++++++++++++++++++ nuttx/sched/sem_post.c | 2 +- nuttx/sched/sem_trywait.c | 7 + nuttx/sched/sem_wait.c | 9 ++ 11 files changed, 435 insertions(+), 26 deletions(-) create mode 100644 nuttx/lib/lib_fgets.c (limited to 'nuttx') diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 823a1c832..61b8970b0 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -3,3 +3,16 @@ * Initial Release * Support for Linux user mode simulation and TI TMS320C5471 (Arm7) provided + +0.1.1 2007-xx-xx Gregory Nutt + + * Corrected an error in interrupt level context switching + for C5471 + * Added fgets logic; verified console read. + * Corrected error in reading from serial port. Improper + use of semaphore can cause deadlock. + * Attempts to use C5471 console from interrupt handlers + can casue errors. Added a special path for this case. + * Refuse callse to sem_wait and sem_trywait from interrupt + handlers. + * Documentation updates diff --git a/nuttx/arch/c5471/src/up_blocktask.c b/nuttx/arch/c5471/src/up_blocktask.c index 6b42d4270..5e0693e2e 100644 --- a/nuttx/arch/c5471/src/up_blocktask.c +++ b/nuttx/arch/c5471/src/up_blocktask.c @@ -95,8 +95,6 @@ void up_block_task(_TCB *tcb, tstate_t task_state) _TCB *rtcb = (_TCB*)g_readytorun.head; boolean switch_needed; - dbg("Blocking TCB=%p\n", tcb); - /* Remove the tcb task from the ready-to-run list. If we * are blocking the task at the head of the task list (the * most likely case), then a context switch to the next diff --git a/nuttx/arch/c5471/src/up_doirq.c b/nuttx/arch/c5471/src/up_doirq.c index f4e07873c..ab1b40d65 100644 --- a/nuttx/arch/c5471/src/up_doirq.c +++ b/nuttx/arch/c5471/src/up_doirq.c @@ -74,6 +74,13 @@ void up_doirq(int irq, uint32* regs) #else if ((unsigned)irq < NR_IRQS) { + /* Current regs non-zero indicates that we are processing + * an interrupt; current_regs is also used to manage + * interrupt level context switches. + */ + + current_regs = regs; + /* Mask and acknowledge the interrupt */ up_maskack_irq(irq); @@ -82,8 +89,15 @@ void up_doirq(int irq, uint32* regs) irq_dispatch(irq, regs); - /* Then unmask it */ + /* Indicate that we are no long in an interrupt handler */ + + current_regs = NULL; + + /* Unmask the last interrupt (global interrupts are still + * disabled. + */ + current_regs = NULL; up_enable_irq(irq); } up_ledoff(LED_INIRQ); diff --git a/nuttx/arch/c5471/src/up_serial.c b/nuttx/arch/c5471/src/up_serial.c index c6d6dc58e..022befd38 100644 --- a/nuttx/arch/c5471/src/up_serial.c +++ b/nuttx/arch/c5471/src/up_serial.c @@ -521,7 +521,7 @@ static inline void up_givesem(sem_t *sem) * characters from the tail of the buffer. */ -static inline void up_recvchars(up_dev_t *dev) +static void up_recvchars(up_dev_t *dev) { uint16 status; int nexthead = dev->recv.head + 1; @@ -800,6 +800,32 @@ static void shutdown(up_dev_t * dev) irqrestore(flags); } +/************************************************************ + * Name: up_irqwrite + ************************************************************/ + +static ssize_t up_irqwrite(up_dev_t *dev, const char *buffer, size_t buflen) +{ + ssize_t ret = buflen; + + /* Force each character through the low level interface */ + + for (; buflen; buflen--) + { + int ch = *buffer++; + up_lowputc(ch); + + /* If this is the console, then we should replace LF with LF-CR */ + + if (ch == '\n') + { + up_lowputc('\r'); + } + } + + return ret; +} + /************************************************************ * Name: up_write ************************************************************/ @@ -810,6 +836,23 @@ static ssize_t up_write(struct file *filep, const char *buffer, size_t buflen) up_dev_t *dev = inode->i_private; ssize_t ret = buflen; + /* We may receive console writes through this path from + * interrupt handlers! In this case, we will need to do + * things a little differently. + */ + + if (up_interrupt_context()) + { + if (dev->isconsole) + { + return up_irqwrite(dev, buffer, buflen); + } + else + { + return ERROR; + } + } + /* Only one user can be accessing dev->xmit.head at once */ up_takesem(&dev->xmit.sem); @@ -827,10 +870,10 @@ static ssize_t up_write(struct file *filep, const char *buffer, size_t buflen) /* Put the character into the transmit buffer */ up_putxmitchar(dev, ch); - + /* If this is the console, then we should replace LF with LF-CR */ - if (ch == '\n') + if (dev->isconsole && ch == '\n') { up_putxmitchar(dev, '\r'); } @@ -895,7 +938,7 @@ static ssize_t up_read(struct file *filep, char *buffer, size_t buflen) } up_enablerxint(dev); - up_takesem(&dev->recv.sem); + up_givesem(&dev->recv.sem); return ret; } diff --git a/nuttx/include/ctype.h b/nuttx/include/ctype.h index 9b62034ff..fb30746de 100644 --- a/nuttx/include/ctype.h +++ b/nuttx/include/ctype.h @@ -64,31 +64,49 @@ ************************************************************/ #define isspace(c) \ - (c == ' ' || c == '\t' || c == '\n' || \ - c == '\r' || c == '\f' || c== '\v') + ((c) == ' ' || (c) == '\t' || (c) == '\n' || \ + (c) == '\r' || (c) == '\f' || c== '\v') /************************************************************ - * Function: isdigit + * Function: isascii * * Description: - * ANSI standard isdigit implementation. + * Checks whether c is a 7-bit unsigned char value that + * fits into the ASCII character set. * ************************************************************/ -#define isdigit(c) \ - (c >= '0' && c <= '9') +#define isascii(c) ((c) >= 0 && (c) <= 0x7f); /************************************************************ - * Function: isascii + * Function: isprint * * Description: - * Checks whether c is a 7-bit unsigned char value that - * fits into the ASCII character set. + * Checks for a printable character (including space) + * + ************************************************************/ + +#define isprint(c) ((c) >= 0x20 && (c) < 0x7f) + +/************************************************************ + * Function: iscntrl + * + * Description: + * Checks for control character. + * + ************************************************************/ + +#define iscontrol(c) (!isprint(c)) + +/************************************************************ + * Function: isdigit + * + * Description: + * ANSI standard isdigit implementation. * ************************************************************/ -#define isascii(c) \ - (c >= 0 && c <= 0177); +#define isdigit(c) ((c) >= '0' && (c) <= '9') /************************************************************ * Function: isxdigit @@ -100,9 +118,9 @@ ************************************************************/ #define isxdigit(c) \ - ((c >= '0' && c <= '9') || \ - (c >= 'a' && c <= 'f') || \ - (c >= 'A' && c <= 'F')) + (((c) >= '0' && (c) <= '9') || \ + ((c) >= 'a' && (c) <= 'f') || \ + ((c) >= 'A' && (c) <= 'F')) /************************************************************ * Function: toupper @@ -113,7 +131,7 @@ ************************************************************/ #define toupper(c) \ - ((c >= 'a' && c <= 'z') ? ((c) - 'a' + 'A') : (c)) + (((c) >= 'a' && (c) <= 'z') ? ((c) - 'a' + 'A') : (c)) /************************************************************ * Function: tolower @@ -124,7 +142,7 @@ ************************************************************/ #define tolower(c) \ - ((c >= 'A' && c <= 'Z') ? ((c) - 'A' + 'a') : (c)) + (((c) >= 'A' && (c) <= 'Z') ? ((c) - 'A' + 'a') : (c)) /************************************************************ * Public Type Definitions diff --git a/nuttx/include/stdio.h b/nuttx/include/stdio.h index f234a861c..426b23714 100644 --- a/nuttx/include/stdio.h +++ b/nuttx/include/stdio.h @@ -224,6 +224,7 @@ EXTERN size_t fread(void *ptr, size_t size, size_t n_items, EXTERN int fseek(FILE *stream, long int offset, int whence); EXTERN size_t fwrite(const void *ptr, size_t size, size_t n_items, FILE *stream); + EXTERN int printf(const char *format, ...); EXTERN int puts(const char *s); EXTERN int rename(const char *source, const char *target); diff --git a/nuttx/lib/Makefile b/nuttx/lib/Makefile index 2189db7a5..cb77499c8 100644 --- a/nuttx/lib/Makefile +++ b/nuttx/lib/Makefile @@ -46,8 +46,8 @@ STRING_SRCS = lib_memset.c lib_memcpy.c lib_memcmp.c lib_memmove.c \ lib_strlen.c lib_strdup.c lib_strtol.c lib_strchr.c CTYPE_SRCS = STDIO_SRCS = lib_fopen.c lib_fclose.c \ - lib_fread.c lib_libfread.c lib_fgetc.c\ - lib_fwrite.c lib_libfwrite.c lib_fflush.c\ + lib_fread.c lib_libfread.c lib_fgetc.c lib_fgets.c \ + lib_fwrite.c lib_libfwrite.c lib_fflush.c \ lib_fputc.c lib_puts.c lib_fputs.c \ lib_ungetc.c \ lib_printf.c lib_vprintf.c lib_fprintf.c lib_rawprintf.c lib_lowprintf.c \ diff --git a/nuttx/lib/lib_fgets.c b/nuttx/lib/lib_fgets.c new file mode 100644 index 000000000..df18c239a --- /dev/null +++ b/nuttx/lib/lib_fgets.c @@ -0,0 +1,306 @@ +/************************************************************ + * lib_fgets.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************/ + +/************************************************************ + * Compilation Switches + ************************************************************/ + +/************************************************************ + * Included Files + ************************************************************/ + +#include +#include +#include +#include + +/************************************************************ + * Definitions + ************************************************************/ + +/************************************************************ + * Private Type Declarations + ************************************************************/ + +/************************************************************ + * Private Function Prototypes + ************************************************************/ + +/************************************************************ + * Global Function Prototypes + ************************************************************/ + +/************************************************************ + * Global Constant Data + ************************************************************/ + +/************************************************************ + * Global Variables + ************************************************************/ + +/************************************************************ + * Private Constant Data + ************************************************************/ + +/************************************************************ + * Private Variables + ************************************************************/ + +/************************************************************ + * Private Functions + ************************************************************/ + +/************************************************************ + * Name: _lib_rawgetc + ************************************************************/ + +static inline int _lib_rawgetc(int fd) +{ + char buffer; + (void)read(fd, &buffer, 1); + return buffer; +} + +/************************************************************ + * Name: _lib_consoleputc + ************************************************************/ + +static inline void _lib_consoleputc(int ch) +{ + char buffer = ch; + (void)write(1, &buffer, 1); +} + +/************************************************************ + * Name: _lib_consoleputs + ************************************************************/ + +static inline void _lib_consoleputs(char *s) +{ + (void)write(1, s, strlen(s)); +} + +/************************************************************ + * Global Functions + ************************************************************/ + +/************************************************************ + * Name: fgets + * + * Description: + * fgets() reads in at most one less than 'n' characters + * from stream and stores them into the buffer pointed to + * by 's'. Reading stops after an EOF or a newline. If a + * newline is read, it is stored into the buffer. A null + * terminator is stored after the last character in the + * buffer. + * + * Assumptions: + * If the stream corresponds to stdin (fd=0) this version + * will assume that we are reading characters from a + * VT100 console and that stdout (fd=1) is also available. + * This will not work well if fd=0 corresponds to a raw + * byte steam. + * + **********************************************************/ + +char *fgets(FAR char *s, int n, FILE *stream) +{ + int escape = 0; + boolean console; + int nch = 0; + + /* Sanity checks */ + + if (!stream || !s || n < 1 || stream->fs_filedes < 0) + { + return NULL; + } + + if (n < 2) + { + *s = '\0'; + return s; + } + + /* Check if the stream is stdin */ + + console = (stream->fs_filedes == 0); + + /* [K is the VT100 command that erases to the end of the line. */ + + if (console) + { + _lib_consoleputs("\033[K"); + } + + /* Read characters until we have a full line. On each + * the loop we must be assured that there are two free bytes + * in the line buffer: One for the next character and one for + * the null terminator. + */ + + for(;;) + { + /* Get the next character */ + + int ch = _lib_rawgetc(stream->fs_filedes); + + /* Are we processing a VT100 escape sequence */ + + if (escape) + { + /* Yes, is it an [, 3 byte sequence */ + + if (ch != 0x5b || escape == 2) + { + /* We are finished with the escape sequence */ + + escape = 0; + ch = 'a'; + } + else + { + /* The next character is the end of a 3-byte sequence. + * NOTE: Some of the [ sequences are longer than + * 3-bytes, but I have not encountered any in normal use + * yet and, so, have not provided the decoding logic. + */ + + escape = 2; + } + } + + /* Check for backspace */ + + else if (ch == 0x08) + { + /* Eliminate that last character in the buffer. */ + + if (nch > 0) + { + nch--; + + if (console) + { + /* Echo the backspace character on the console */ + + _lib_consoleputc(ch); + } + } + } + + /* Check for the beginning of a VT100 escape sequence */ + + else if (console && ch == 0x1b) + { + /* The next character is escaped */ + + escape = 1; + } + + /* Check for end-of-line or end-of-file */ + + else if (ch == 0x0d) + { + /* The newline is stored in the buffer along + * with the null terminator. + */ + + s[nch++] = '\n'; + s[nch] = '\0'; + + if (console) + { + /* Echo the newline to the console */ + + _lib_consoleputc('\n'); + } + + return s; + } + + /* Check for end-of-line or end-of-file */ + + else if (ch == EOF) + { + /* Terminate the line */ + + s[nch] = '\0'; + return s; + } + + /* Otherwise, check if the character is printable and, + * if so, put the character in the line buffer + */ + + else if (isprint(ch)) + { + s[nch++] = ch; + + if (console) + { + /* Echo the character to the console */ + + _lib_consoleputc(ch); + } + + /* Check if there is room for another character + * and the line's null terminator. If not then + * we have to end the line now. + */ + + if (nch + 1 >= n) + { + s[nch] = '\0'; + return s; + } + } + } + +} + +/************************************************************ + * Name: gets + * + * Description: + * gets() reads a line from stdin into the buffer pointed + * to by s until either a terminating newline or EOF, + * which it replaces with '\0'. No check for buffer + * overrun is performed + * + **********************************************************/ + +/* gets() is not supported because it is inherently un-safe */ diff --git a/nuttx/sched/sem_post.c b/nuttx/sched/sem_post.c index 3b4fac368..857b20def 100644 --- a/nuttx/sched/sem_post.c +++ b/nuttx/sched/sem_post.c @@ -139,7 +139,7 @@ int sem_post(sem_t *sem) */ for (stcb = (FAR _TCB*)g_waitingforsemaphore.head; - ((stcb) && (stcb->waitsem != sem)); + (stcb && stcb->waitsem != sem); stcb = stcb->flink); if (stcb) diff --git a/nuttx/sched/sem_trywait.c b/nuttx/sched/sem_trywait.c index 384eff0a0..dc65f8f58 100644 --- a/nuttx/sched/sem_trywait.c +++ b/nuttx/sched/sem_trywait.c @@ -102,6 +102,13 @@ int sem_trywait(sem_t *sem) irqstate_t saved_state; int ret = ERROR; + if (up_interrupt_context()) + { + /* We do not want to set the errno in this case */ + + return ERROR; + } + /* Assume any errors reported are due to invalid arguments. */ *get_errno_ptr() = EINVAL; diff --git a/nuttx/sched/sem_wait.c b/nuttx/sched/sem_wait.c index 7893b39ba..4d82dd41a 100644 --- a/nuttx/sched/sem_wait.c +++ b/nuttx/sched/sem_wait.c @@ -103,6 +103,15 @@ int sem_wait(sem_t *sem) int ret = ERROR; irqstate_t saved_state; + /* This API should not be called from interrupt handlers */ + + if (up_interrupt_context()) + { + /* We do not want to set the errno in this case */ + + return ERROR; + } + /* Assume any errors reported are due to invalid arguments. */ *get_errno_ptr() = EINVAL; -- cgit v1.2.3