
#include "kernel/kernel.h"

#if CONFIG_OXPCIE

/* Documentation is at http://www.plxtech.com/products/uart/oxpcie952 */

#include "oxpcie.h"
#include "serial.h"

PRIVATE unsigned char *oxpcie_vaddr = NULL;

PUBLIC void oxpcie_set_vaddr(unsigned char *vaddr)
{
	oxpcie_vaddr = vaddr;
}

PRIVATE void oxpcie_init(void)
{
	printf("oxpcie_init\n");
	/* Enable access to EFR and DLM+DLL */
	OXPCIE_LCR = 0xBF;

	/* Set FICR[1] to increase FIFO */
	OXPCIE_FICR = 0x01;

	/* Set enhanced mode [4]
	 * no RTS/CTS [7:6]
	 * no special char detection [5]
	 * no in-band receive flow control [1:0]
	 * no in-band transmit flow control [3:2]
	 */
	OXPCIE_EFR  = 0x10; 

	/* Set divisor register to 115200 baud. */
	OXPCIE_DLM = 0x00;
	OXPCIE_DLL = 0x22;

	/* Forget DLM and DLL, set LCR to config. */
	OXPCIE_LCR = LCR_CONFIG;
	OXPCIE_LCR = LCR_CONFIG;

	OXPCIE_TCR = 0x01;
	OXPCIE_CPR = 0x20;
	OXPCIE_CPR2 = 0;
}

PUBLIC void oxpcie_putc(char c)
{
	static int inuse = 0;

	if(vm_running && oxpcie_vaddr && !inuse) {
        	int i;
		static int init_done;
		inuse = 1;

		if(!init_done) {
			oxpcie_init();
			init_done = 1;
		}

        	for (i= 0; i<100000; i++) {
			if(OXPCIE_LSR & LSR_THRE)
                       		break;
		}
		OXPCIE_THR = c;
		inuse = 0;
	}
}

PUBLIC int oxpcie_in(void)
{
	if(vm_running && oxpcie_vaddr) {
		int lsr;
		lsr = OXPCIE_LSR;
		if(lsr & LSR_DR)
			return (int) OXPCIE_RBR;
	}

	return -1;
}

#endif
