calypso/uart.c: Fix array bounds checking
[osmocom-bb.git] / src / target / firmware / calypso / uart.c
index 7e68edc..bcb56bd 100644 (file)
 #include <string.h>
 #include <stdio.h>
 
+#include <defines.h>
 #include <console.h>
 #include <comm/sercomm.h>
 
 #include <calypso/irq.h>
-#include <calypso/uart.h>
+#include <uart.h>
 
 #define BASE_ADDR_UART_MODEM   0xffff5000
 #define OFFSET_IRDA            0x800
@@ -42,7 +43,7 @@
 #define LCR7BIT                0x80
 #define LCRBFBIT       0x40
 #define MCR6BIT                0x20
-#define REG_OFFS(m)    ((m) &= ~(LCR7BIT|LCRBFBIT|MCR6BIT))
+#define REG_OFFS(m)    ((m) & ~(LCR7BIT|LCRBFBIT|MCR6BIT))
 /* read access LCR[7] = 0 */
 enum uart_reg {
        RHR     = 0,
@@ -126,12 +127,12 @@ static void uart_set_lcr7bit(int uart, int on)
 static uint8_t old_lcr;
 static void uart_set_lcr_bf(int uart, int on)
 {
-       old_lcr = readb(UART_REG(uart, LCR));
-
-       if (on)
+       if (on) {
+               old_lcr = readb(UART_REG(uart, LCR));
                writeb(0xBF, UART_REG(uart, LCR));
-       else
+       } else {
                writeb(old_lcr, UART_REG(uart, LCR));
+       }
 }
 
 /* Enable or disable the TCR_TLR latch bit in MCR[6] */
@@ -190,7 +191,7 @@ static uint8_t uart_reg_read(int uart, enum uart_reg reg)
        return ret;
 }
 
-static void uart_irq_handler_cons(enum irq_nr irq)
+static void uart_irq_handler_cons(__unused enum irq_nr irqnr)
 {
        const uint8_t uart = CONS_UART_NR;
        uint8_t iir;
@@ -223,7 +224,7 @@ static void uart_irq_handler_cons(enum irq_nr irq)
        }
 }
 
-static void uart_irq_handler_sercomm(enum irq_nr irq)
+static void uart_irq_handler_sercomm(__unused enum irq_nr irqnr)
 {
        const uint8_t uart = SERCOMM_UART_NR;
        uint8_t iir, ch;
@@ -259,10 +260,13 @@ static void uart_irq_handler_sercomm(enum irq_nr irq)
                }
                break;
        case IIR_INT_TYPE_MSR:
+               printf("UART IRQ MSR\n");
                break;
        case IIR_INT_TYPE_RX_STATUS_ERROR:
+               printf("UART IRQ RX_SE\n");
                break;
        case IIR_INT_TYPE_XOFF:
+               printf("UART IRQXOFF\n");
                break;
        }
 }
@@ -272,21 +276,25 @@ static const uint8_t uart2irq[] = {
        [1]     = IRQ_UART_MODEM,
 };
 
-void uart_init(uint8_t uart)
+void uart_init(uint8_t uart, uint8_t interrupts)
 {
        uint8_t irq = uart2irq[uart];
 
        uart_reg_write(uart, IER, 0x00);
        if (uart == CONS_UART_NR) {
                cons_init();
-               irq_register_handler(irq, &uart_irq_handler_cons);
-               irq_config(irq, 0, 0, 0xff);
-               irq_enable(irq);
+               if(interrupts) {
+                       irq_register_handler(irq, &uart_irq_handler_cons);
+                       irq_config(irq, 0, 0, 0xff);
+                       irq_enable(irq);
+               }
        } else {
                sercomm_init();
-               irq_register_handler(irq, &uart_irq_handler_sercomm);
-               irq_config(irq, 0, 0, 0xff);
-               irq_enable(irq);
+               if(interrupts) {
+                       irq_register_handler(irq, &uart_irq_handler_sercomm);
+                       irq_config(irq, 0, 0, 0xff);
+                       irq_enable(irq);
+               }
                uart_irq_enable(uart, UART_IRQ_RX_CHAR, 1);
        }
 #if 0
@@ -295,6 +303,16 @@ void uart_init(uint8_t uart)
                writeb(UART_REG_UIR, 0x00);
        }
 #endif
+
+       /* if we don't initialize these, we get strange corruptions in the
+          received data... :-( */
+       uart_reg_write(uart,  MDR1, 0x07); /* turn off UART */
+       uart_reg_write(uart,  XON1, 0x00); /* Xon1/Addr Register */
+       uart_reg_write(uart,  XON2, 0x00); /* Xon2/Addr Register */
+       uart_reg_write(uart, XOFF1, 0x00); /* Xoff1 Register */
+       uart_reg_write(uart, XOFF2, 0x00); /* Xoff2 Register */
+       uart_reg_write(uart,   EFR, 0x00); /* Enhanced Features Register */
+
        /* select  UART mode */
        uart_reg_write(uart, MDR1, 0);
        /* no XON/XOFF flow control, ENHANCED_EN, no auto-RTS/CTS */
@@ -312,6 +330,14 @@ void uart_init(uint8_t uart)
        uart_set_lcr7bit(uart, 0);
 }
 
+void uart_poll(uint8_t uart) {
+       if(uart == CONS_UART_NR) {
+               uart_irq_handler_cons(0);
+       } else {
+               uart_irq_handler_sercomm(0);
+       }
+}
+
 void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on)
 {
        uint8_t ier = uart_reg_read(uart, IER);
@@ -356,10 +382,28 @@ int uart_putchar_nb(uint8_t uart, int c)
 
 int uart_getchar_nb(uint8_t uart, uint8_t *ch)
 {
-       if (!(readb(UART_REG(uart, LSR)) & 0x01))
+       uint8_t lsr;
+
+       lsr = readb(UART_REG(uart, LSR));
+
+       /* something strange happened */
+       if (lsr & 0x02)
+               printf("LSR RX_OE\n");
+       if (lsr & 0x04)
+               printf("LSR RX_PE\n");
+       if (lsr & 0x08)
+               printf("LSR RX_FE\n");
+       if (lsr & 0x10)
+               printf("LSR RX_BI\n");
+       if (lsr & 0x80)
+               printf("LSR RX_FIFO_STS\n");
+
+       /* is the Rx FIFO empty? */
+       if (!(lsr & 0x01))
                return 0;
 
        *ch = readb(UART_REG(uart, RHR));
+       //printf("getchar_nb(%u) = %02x\n", uart, *ch);
        return 1;
 }
 
@@ -383,7 +427,7 @@ int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt)
 {
        uint16_t div;
 
-       if (bdrt > ARRAY_SIZE(divider))
+       if (bdrt >= ARRAY_SIZE(divider))
                return -1;
 
        div = divider[bdrt];