From 89b91918d9b7ce7f25847616e0c318cc13f3b2cc Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 10 Mar 2007 00:17:29 +0000 Subject: [PATCH] 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 --- arch/c5471/src/up_blocktask.c | 2 -- arch/c5471/src/up_doirq.c | 16 ++++++++++- arch/c5471/src/up_serial.c | 51 ++++++++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/arch/c5471/src/up_blocktask.c b/arch/c5471/src/up_blocktask.c index 6b42d42702..5e0693e2e3 100644 --- a/arch/c5471/src/up_blocktask.c +++ b/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/arch/c5471/src/up_doirq.c b/arch/c5471/src/up_doirq.c index f4e07873cd..ab1b40d655 100644 --- a/arch/c5471/src/up_doirq.c +++ b/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/arch/c5471/src/up_serial.c b/arch/c5471/src/up_serial.c index c6d6dc58ef..022befd380 100644 --- a/arch/c5471/src/up_serial.c +++ b/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; }