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;
}
Example #2
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__);
	}
}
Example #3
0
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);
}
Example #5
0
/*
 * 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);
}