#ifndef CONSOLE_H
#define CONSOLE_H

#include "compiler.h"
#include "io.h"

#define CON_FLOW_CTL	0	/* Block on connected and output full? */
#define CON_OUT_OF_LINE	0
#define CON_DELAY	0	/* us delay after output */

void __fmt_printf(1,0) con_vprintf(const char *, va_list);
void __fmt_printf(1,2) con_printf(const char *, ...);

static __always_inline void __con_wait_tx_ready(void)
{
    /*
     * If CON_FLOW_CTL is set, wait here if the TX buffer is above
     * the high index mark *if* we are connected to a host
     */
    while (CON_FLOW_CTL &&
	   (CON_STATUS & (TTY_STATUS_TX_HIGH|TTY_STATUS_DTR_IN))
	   == (TTY_STATUS_TX_HIGH|TTY_STATUS_DTR_IN))
	relax();
}

static __always_inline void __con_putc(char c)
{
    if (c == '\n') {
	CON_DATA = '\r';
	udelay(CON_DELAY);
    }
    CON_DATA = c;
    udelay(CON_DELAY);
}

static __always_inline void _con_putc(char c)
{
    __con_wait_tx_ready();
    __con_putc(c);
}

static __always_inline void _con_puts(const char *str)
{
    char c;

    __con_wait_tx_ready();

    while ((c = *str++))
	__con_putc(c);
}

#if CON_OUT_OF_LINE

void con_putc(char c);
void con_puts(const char *);

#else

/* Simple enough to inline if we don't care about flow control */

static __always_inline void con_putc(char c)
{
    _con_putc(c);
}

static __always_inline void con_puts(const char *str)
{
    _con_puts(str);
}

#endif

static __always_inline void con_flush_unconditional(void)
{
    while (!(CON_STATUS & TTY_STATUS_TX_EMPTY))
	relax();
}

static __always_inline void con_flush(void)
{
    if (CON_FLOW_CTL)
	con_flush_unconditional();
}

void con_print_hex(unsigned int); /* For pre-SDRAM capable code */
void con_hexdump(const void *data, size_t len); /* For debugging */

#endif /* CONSOLE_H */
