zeta-v2: adopt UART code from P112, implement tty_setup
authorSergey Kiselev <skiselev@gmail.com>
Thu, 12 Mar 2015 04:58:39 +0000 (21:58 -0700)
committerSergey Kiselev <skiselev@gmail.com>
Thu, 12 Mar 2015 04:58:39 +0000 (21:58 -0700)
Kernel/platform-zeta-v2/devtty.c
Kernel/platform-zeta-v2/devtty.h
Kernel/platform-zeta-v2/kernel.def
Kernel/platform-zeta-v2/main.c
Kernel/platform-zeta-v2/zeta-v2.s

index f9ac01b..2523294 100644 (file)
@@ -13,33 +13,95 @@ char tbufp[TTYSIZ];
 #endif
 
 struct  s_queue  ttyinq[NUM_DEV_TTY+1] = {       /* ttyinq[0] is never used */
-    {   NULL,    NULL,    NULL,    0,        0,       0    },
-    {   tbuf1,   tbuf1,   tbuf1,   TTYSIZ,   0,   TTYSIZ/2 },
+       {NULL,  NULL,   NULL,   0,      0,      0},
+       {tbuf1, tbuf1,  tbuf1,  TTYSIZ, 0,      TTYSIZ/2},
 #ifdef CONFIG_PPP
-    {   tbufp,   tbufp,   tbufp,   TTYSIZ,   0,   TTYSIZ/2 },
+       {tbufp, tbufp,  tbufp,  TTYSIZ, 0,      TTYSIZ/2},
 #endif
 };
 
-/* FIXME: implement */
+uint16_t divisor_table[16] = {
+       0, UART_CLOCK / 16 / 50, UART_CLOCK / 16 / 75, UART_CLOCK / 16 / 110,
+       UART_CLOCK / 16 / 134, UART_CLOCK / 16 / 150, UART_CLOCK / 16 / 300,
+       UART_CLOCK / 16 / 600, UART_CLOCK / 16 / 1200, UART_CLOCK / 16 / 2400,
+       UART_CLOCK / 16 / 4800, UART_CLOCK / 16 / 9600,
+       UART_CLOCK / 16 / 19200, UART_CLOCK / 16 / 38400,
+       UART_CLOCK / 16 / 57600, UART_CLOCK / 16 / 115200
+};
+
 void tty_setup(uint8_t minor)
 {
-    minor;
+       uint16_t b;
+       uint8_t lcr = 0;
+       if (minor == 1) {
+               b = ttydata[minor].termios.c_cflag & CBAUD;
+               if (b > 0 && b < 16) {
+                       UART0_LCR = 0x80;       /* LCR = DLAB ON */
+                       UART0_DLL = divisor_table[b] & 0xFF;
+                       UART0_DLH = divisor_table[b] >> 8;
+               }
+               /* word length 5(00), 6(01), 7(10), or 8(11) */
+               lcr = (ttydata[minor].termios.c_cflag & CSIZE) >> 4;
+               /* stop bits 1(0), or 2(1) */
+               lcr |= (ttydata[minor].termios.c_cflag & CSTOPB) >> 4;
+               /* parity disable(0), or enable(1) */
+               lcr |= (ttydata[minor].termios.c_cflag & PARENB) >> 5;
+               /* parity odd(0), or even(1) */
+               lcr |= ((ttydata[minor].termios.c_cflag & PARODD) ^ PARODD) >> 5;
+               UART0_LCR = lcr;
+               UART0_MCR = 0x03; /* DTR = ON, RTS = ON */
+       }
 }
 
-/* FIXME: implement (although /DCD is hardwired to GND) */
 int tty_carrier(uint8_t minor)
 {
-    minor;
-    return 1;
+       uint8_t c;
+       if (minor == 1) {
+               c = UART0_MSR;
+               return (c & 0x80) ? 1 : 0; /* test DCD */
+       }
+       return 1;
 }
 
-void tty_interrupt(void)
+void tty_pollirq_uart0(void)
 {
-       uint8_t reg = UART0_LSR;
-       if (reg & 0x01) {
-               /* data available */
-               reg = UART0_RBR;
-               tty_inproc(1, reg);
+       uint8_t iir, msr, lsr;
+       while (true) {
+               iir = UART0_IIR;
+               lsr = UART0_LSR;
+               /* IRR bits
+                * 3 2 1 0
+                * -------
+                * x x x 1     no interrupt pending
+                * 0 1 1 0  6  LSR changed -- read the LSR
+                * 0 1 0 0  4  receive FIFO >= threshold
+                * 1 1 0 0  C  received data sat in FIFO for a while
+                * 0 0 1 0  2  transmit holding register empty
+                * 0 0 0 0  0  MSR changed -- read the MSR
+                */
+               switch (iir & 0x0F) {
+               case 0x0: /* MSR changed */
+               case 0x2: /* transmit register empty */
+                       msr = UART0_MSR;
+                       if ((msr & 0x10) && (lsr & 0x20)){
+                               /* CTS high, transmit reg empty */
+                               tty_outproc(1);
+                       }
+                       /* fall through */
+               case 0x6: /* LSR changed */
+                       /* we already read the LSR register so int has cleared */
+                       UART0_IER = 0x01; /* enable only receive interrupts */
+                       break;
+               case 0x4: /* receive (FIFO >= threshold) */
+               case 0xC: /* receive (timeout waiting for FIFO to fill) */
+                       while (lsr & 0x01) { /* Data ready */
+                               tty_inproc(1, UART0_RBR);
+                               lsr = UART0_LSR;
+                       }
+                       break;
+               default:
+                       return;
+               }
        }
 }
 
@@ -65,15 +127,22 @@ void tty_putc(uint8_t minor, unsigned char c)
 
 void tty_sleeping(uint8_t minor)
 {
-       minor;
+       if (minor == 1) {
+               UART0_IER = 0x0B; /* enable all but LSR interrupt */
+       }
 }
 
 ttyready_t tty_writeready(uint8_t minor)
 {
-       uint8_t reg;
+       uint8_t c;
        if (minor == 1) {
-               reg = UART0_LSR;
-               return (reg & 0x20) ? TTY_READY_NOW : TTY_READY_SOON;
+               c = UART0_MSR;
+               if ((c & 0x10) == 0) /* CTS not asserted? */
+                       return TTY_READY_LATER;
+               c = UART0_LSR;
+               if (c & 0x20) /* THRE? */
+                       return TTY_READY_NOW;
+               return TTY_READY_SOON;
        }
        return TTY_READY_NOW;
 }
index 242631e..709b94e 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef __DEVTTY_DOT_H__
 #define __DEVTTY_DOT_H__
+
+#define UART_CLOCK 1843200UL
 void tty_putc(uint8_t minor, unsigned char c);
-void tty_interrupt(void);
+void tty_pollirq_uart0(void);
 
 #ifdef CONFIG_PPP
 void tty_poll_ppp(void);
index ae762f1..cacebb2 100644 (file)
@@ -12,7 +12,7 @@ PROGLOAD              .equ    0x0100
 
 ; Zeta SBC V2 mnemonics for I/O ports etc
 
-CONSOLE_RATE           .equ    38400
+CONSOLE_RATE           .equ    9600
 
 CPU_CLOCK_KHZ          .equ    20000
 
index 2bd5689..73afac0 100644 (file)
@@ -4,7 +4,7 @@
 #include <devtty.h>
 #include "config.h"
 #ifdef CONFIG_FLOPPY
-#include "devfd.h"
+#include <devfd.h>
 #endif
 
 extern unsigned char irqvector;
@@ -31,7 +31,7 @@ void platform_interrupt(void)
                        timer_interrupt(); 
                        return;
                case 2:
-                       tty_interrupt();
+                       tty_pollirq_uart0();
                        return;
                default:
                        return;
index 8ebd8db..0b6113b 100644 (file)
@@ -63,12 +63,12 @@ init_hardware:
        out (UART0_DLL),a               ; set low byte of divisor
        ld a,#CONSOLE_DIVISOR_HIGH      ; baud rate divisor - high byte
        out (UART0_DLH),a               ; set high byte of divisor
-       ld a,#3                         ; value for LCR and MCR
+       ld a,#0x03                              ; value for LCR and MCR
        out (UART0_LCR),a               ; 8 bit data, 1 stop, no parity
        out (UART0_MCR),a               ; DTR ON, RTS ON
-       ld a,#6                         ; disable and reset FIFOs
-       out (UART0_FCR),a
-       ld a,#1                         ; enable receive data available
+       ld a,#0x07                      ; enable and clear FIFOs
+       out (UART0_FCR),a               ; interrupt theshold 1 byte
+       ld a,#0x01                      ; enable receive data available
        out (UART0_IER),a               ; interrupt
        ; initialize CTC
        ld a,#0x47                      ; counter mode, disable interrupts