The unified diff between revisions [961b04dd..] and [cbddc8b3..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'uart.c'

#
# old_revision [961b04ddb07ba2b5dd6bccfa66a03e442e40d8f0]
# new_revision [cbddc8b347cfe68cf634efaf314c99652ed27527]
#
# patch "uart.c"
#  from [b336e227dc442fef728c0a695671328c7a265dd1]
#    to [cd75769ab8ffb66cd0ff19a158def1fadbbbe56f]
#
============================================================
--- uart.c	b336e227dc442fef728c0a695671328c7a265dd1
+++ uart.c	cd75769ab8ffb66cd0ff19a158def1fadbbbe56f
@@ -1,7 +1,11 @@
 #include "uart.h"
+#include "types.h"
+#include "interrupt.h"
 
 #define UARTBASE 0xE000C000
 
+#define FP0XVAL (*((volatile unsigned int *) 0x3FFFC014))
+
 #define RBR 0x00
 #define THR 0x00
 #define DLL 0x00
@@ -22,6 +26,15 @@
 #define U0THRE ((UREG(LSR) & (1<<5))) /* UART0 transmitter holding register is empty */
 #define U0DR ((UREG(LSR) & (1<<0))) /* UART0 data ready */
 
+#define UART_BUFSIZE 128
+
+char uart_txbuf[UART_BUFSIZE];
+volatile int uart_txread;
+volatile int uart_txwrite;
+volatile bool tx_running;
+
+void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void);
+
 void init_uart(void)
 {
 	UREG(FDR) = 0x10; /* DivAddVal = 0, MulVal = 1 */
@@ -31,13 +44,74 @@ void init_uart(void)
 	UREG(DLL) = 0x08; /* 14745600 / (16*115200) */
 	UREG(LCR) = 0x13;
 	UREG(FCR) = 0x07;
+
+	uart_txread = 0;
+	uart_txwrite = 0;
+	tx_running = FALSE;
+	interrupt_register(UART0, uart_interrupt_handler);
+
+	UREG(IER) = 0x02; /* THRE interrupt enable */
 }
 
 void putch(char c) {
-	while (!U0THRE);
-	UREG(THR) = c;
+	/* Wait for space in the buffer */
+	while (uart_txread == ((uart_txwrite+1) % UART_BUFSIZE));
+
+	if (uart_txread == uart_txwrite) {
+		if (U0THRE) {
+			tx_running = TRUE;
+			UREG(THR) = c;
+			return;
+		}
+	}
+
+	uart_txbuf[uart_txwrite] = c;
+	uart_txwrite = (uart_txwrite + 1) % UART_BUFSIZE;
+
+	if (!tx_running) {
+		if (uart_txread != uart_txwrite) {
+			tx_running = TRUE;
+			uart_txread = (uart_txread + 1) % UART_BUFSIZE;
+			UREG(THR) = c;
+		}
+	}
 }
 
+void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void)
+{
+	bool active = FALSE;
+	int source;
+	int i;
+	/* uart_txread and uart_txwrite are volatile. We don't need
+	 * to treat them as such in this handler, so let the compiler
+	 * have an easier time.
+	 */
+	int local_txwrite = uart_txwrite;
+	int local_txread = uart_txread;
+
+	source = UREG(IIR);
+
+	/* For now we assume that all interrupts are actually THR empty
+	 * interrupts. Actually check this when we do more things with
+	 * the UART
+	 */
+
+	if (U0THRE) {
+		for (i = 0; (i < 16) && (local_txwrite != local_txread); i++) {
+			UREG(THR) = uart_txbuf[local_txread];
+			local_txread = (local_txread + 1) % UART_BUFSIZE;
+			active = TRUE;
+		}
+	}
+
+	uart_txread = local_txread;
+
+	if (!active)
+		tx_running = FALSE;
+
+	interrupt_clear();
+}
+
 void putstr(char *s) {
 	while (*s) putch(*s++);
 }
@@ -74,6 +148,8 @@ char getch(void) {
 }
 
 char getch(void) {
-	while (!U0DR);
+	while (!U0DR) {
+		FP0XVAL ^= 0x04000000;
+	}
 	return UREG(RBR);
 }