int buff_getc(buffer_t *bptr, char * c) { static intrspin_t spin; InterruptLock(&spin); if(bptr->cnt == 0) { InterruptUnlock(&spin); return (-1); } *c = *bptr->tail; --bptr->cnt; if(++bptr->tail >= &bptr->buff[bptr->bufsize]) { bptr->tail = bptr->buff; } InterruptUnlock(&spin); return 0; }
void omap_clock_enable(DEV_OMAP* dev, clk_enable_t clk_cfg) { int enable_rc = 0; int functional_rc = 0; /* Our idle state can be changed by the ISR so we must use a spinlock */ InterruptLock(&dev->idle_spinlock); /* Only enable clocks if they aren't enabled already */ if (dev->idle == 0) { goto done; } if (dev->clkctrl_base) { /* Enable the clock */ out32(dev->clkctrl_base, OMAP_CLKCTRL_MODMODE_ENABLE); /* Wait for the module mode to have been written */ enable_rc = poll_for_condition(dev->clkctrl_base, OMAP_CLKCTRL_MODMODE_MASK, OMAP_CLKCTRL_MODMODE_ENABLE); /* Wait for the module idle status to report "fully functional" */ functional_rc = poll_for_condition(dev->clkctrl_base, OMAP_CLKCTRL_IDLEST_MASK, OMAP_CLKCTRL_IDLEST_FUNCTIONAL); /* Re-configure clock if specified otherwise simply skip it */ if (clk_cfg != clk_enable_skip) { /* Set the idle mode to smart idle with wake up */ set_port(dev->port[OMAP_UART_SYSC], OMAP_UART_SYSC_IDLEMODE_MASK, clk_cfg); } /* Enable the CTS wakeup */ write_omap(dev->port[OMAP_UART_WER], OMAP_UART_WER_CTS_ENABLE); /* Indicate clocks are enabled */ dev->idle = 0; } done: #ifdef WINBT /* clear CTS debounce timer and OHW_PAGED flag */ if (dev->tty.un.s.spare_tmr > 0) { dev->tty.un.s.spare_tmr = 0; if (dev->tty.flags & OHW_PAGED) atomic_clr (&dev->tty.flags, OHW_PAGED); } #endif omap_uart_ctx_restore(dev); InterruptUnlock(&dev->idle_spinlock); /* Don't slog while interrupts are disabled - otherwise slogf() will re-enable interrupts */ if (enable_rc) { slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "%s: Failed to set module mode to 'enabled'", __FUNCTION__); } if (functional_rc) { slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "%s: Module failed to report 'fully functional'", __FUNCTION__); } }
void omap_clock_disable(DEV_OMAP* dev) { int rc = 0; /* Our idle state can be changed by the ISR so we must use a spinlock */ InterruptLock(&dev->idle_spinlock); /* Only disable clocks if needed */ if (dev->idle == 1) { goto done; } if (dev->clkctrl_base) { /* Indicate clocks are disabled */ dev->idle = 1; /* Save UART context */ omap_uart_ctx_save(dev); /* Set the idle mode to smart idle with wake up */ write_omap(dev->port[OMAP_UART_SYSC], OMAP_UART_SYSC_IDLEMODE_SMARTWAKEUP | OMAP_UART_SYSC_ENAWAKEUP_ENABLE | OMAP_UART_SYSC_AUTOIDLE_ENABLE); /* Enable the wakeup event */ set_port(dev->port[OMAP_UART_SCR], OMAP_SCR_WAKEUPEN, OMAP_SCR_WAKEUPEN); /* Disable the clock */ out32(dev->clkctrl_base, OMAP_CLKCTRL_MODMODE_DISABLE); /* Wait for the module mode to have been written */ rc = poll_for_condition(dev->clkctrl_base, OMAP_CLKCTRL_MODMODE_MASK, OMAP_CLKCTRL_MODMODE_DISABLE); } done: InterruptUnlock(&dev->idle_spinlock); /* Don't slog while interrupts are disabled - otherwise slogf() will re-enable interrupts */ if (rc) { slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "%s: Failed to set module mode to 'disabled'", __FUNCTION__); } }
int buff_putc(buffer_t *bptr, char c) { static intrspin_t spin; InterruptLock(&spin); if(bptr->cnt < bptr->bufsize) { bptr->cnt++; *bptr->head++ = c; if(bptr->head >= &bptr->buff[bptr->bufsize]) { bptr->head = bptr->buff; } } InterruptUnlock(&spin); return(bptr->cnt); }
/* * Serial interrupt handler */ const struct sigevent * ser_intr(void *area, int id) { int status, cnt; unsigned char msr, lsr; DEV_OMAP *dev = area; struct sigevent *event = NULL; unsigned iir; uintptr_t *port = dev->port; #ifdef PWR_MAN /* Our idle state can be changed by a devctl so we must use a spinlock */ InterruptLock(&dev->idle_spinlock); #endif while (1) { status = 0; #ifdef PWR_MAN if (dev->idle) { omap_clock_enable_isr(dev); #ifdef WINBT omap_force_rts(dev, 0); // once we are in idle mode the only interrupt that can wake us up is from am CTS line change tti(&dev->tty, TTI_OHW_STOP); // start a spare timer for debouncing, if this timer actually // expires, then this was a CTS glitch, if the timer // is cleared by having data on the RX line, it will send up the // oband notification to wake up the host. dev->signal_oband_notification = 1; if( dev->tty.un.s.spare_tmr == 0 ){ atomic_set (&dev->tty.eflags, EVENT_TIMER_QUEUE); dev->tty.un.s.spare_tmr = 4; // queue the event here because the switch statement can just exit // without actually queuing the event with setting the status flag if((dev->tty.flags & EVENT_QUEUED) == 0) { event = &ttyctrl.event; dev_lock(&ttyctrl); ttyctrl.event_queue[ttyctrl.num_events++] = &dev->tty; atomic_set(&dev->tty.flags, EVENT_QUEUED); dev_unlock(&ttyctrl); continue; } } #endif // End of #ifdef WINBT } unsigned ssr = read_omap(port[OMAP_UART_SSR]); if (ssr & OMAP_SSR_WAKEUP_STS) { /* Clear the wake up interrupt */ set_port(port[OMAP_UART_SCR], OMAP_SCR_WAKEUPEN, 0); } #endif iir = read_omap(port[OMAP_UART_IIR]) & OMAP_II_MASK; switch(iir) { case OMAP_II_RX: // Receive data case OMAP_II_RXTO: // Receive data timeout case OMAP_II_LS: // Line status change cnt = 0; lsr = read_omap(port[OMAP_UART_LSR]); do { if( lsr & (OMAP_LSR_BI|OMAP_LSR_OE|OMAP_LSR_FE|OMAP_LSR_PE) ) { // Error character status |= process_lsr(dev, lsr); } else { // Good character status |= tti(&dev->tty, (read_omap(port[OMAP_UART_RHR])) & 0xff); cnt++; } lsr = read_omap(port[OMAP_UART_LSR]); } while(lsr & OMAP_LSR_RXRDY && cnt < FIFO_SIZE); #ifdef WINBT if( cnt && dev->signal_oband_notification ){ // received data after a CTS wake up // notify the host that it's a valid CTS wakeup. dev->signal_oband_notification = 0; dev->tty.oband_data |= _OBAND_SER_MS; atomic_set(&dev->tty.flags, OBAND_DATA); atomic_set(&dev->tty.flags, EVENT_NOTIFY_OBAND); status |= 1; } if (cnt && dev->tty.un.s.spare_tmr) { // received data, clear spare timer dev->tty.un.s.spare_tmr = 0; } #endif break; case OMAP_II_TX: // Transmit buffer empty // disable thr interrupt set_port(dev->port[OMAP_UART_IER], OMAP_IER_THR, 0); dev->tty.un.s.tx_tmr = 0; /* Send event to io-char, tto() will be processed at thread time */ atomic_set(&dev->tty.flags, EVENT_TTO); status |= 1; break; case OMAP_II_MS: // Modem change msr = read_omap(port[OMAP_UART_MSR]); if(msr & OMAP_MSR_DDCD) { status |= tti(&dev->tty, (msr & OMAP_MSR_DCD) ? TTI_CARRIER : TTI_HANGUP); } if((msr & OMAP_MSR_DCTS) && (dev->tty.c_cflag & OHFLOW)) { status |= tti(&dev->tty, (msr & OMAP_MSR_CTS) ? TTI_OHW_CONT : TTI_OHW_STOP); } /* OBAND notification of Modem status change */ dev->tty.oband_data |= _OBAND_SER_MS; atomic_set(&dev->tty.flags, OBAND_DATA); atomic_set(&dev->tty.flags, EVENT_NOTIFY_OBAND); status |= 1; break; case OMAP_II_NOINTR: // No interrupt if (read_omap(port[OMAP_UART_SSR]) & OMAP_SSR_WAKEUP_STS) { // Wake up interrupt set_port(port[OMAP_UART_SCR], OMAP_SCR_WAKEUPEN, 0); // clear wakeup interrupt set_port(port[OMAP_UART_SCR], OMAP_SCR_WAKEUPEN, OMAP_SCR_WAKEUPEN); // re-enable wakeup interrupt } default: goto done; } if (status) { if((dev->tty.flags & EVENT_QUEUED) == 0) { event = &ttyctrl.event; dev_lock(&ttyctrl); ttyctrl.event_queue[ttyctrl.num_events++] = &dev->tty; atomic_set(&dev->tty.flags, EVENT_QUEUED); dev_unlock(&ttyctrl); } } } done: #ifdef PWR_MAN InterruptUnlock(&dev->idle_spinlock); #endif return (event); }