rc2014: add all the tty setup support
authorAlan Cox <alan@linux.intel.com>
Tue, 2 Oct 2018 11:44:54 +0000 (12:44 +0100)
committerAlan Cox <alan@linux.intel.com>
Tue, 2 Oct 2018 11:44:54 +0000 (12:44 +0100)
Kernel/platform-rc2014/devtty.c
Kernel/platform-rc2014/rc2014.h
Kernel/platform-rc2014/rc2014.s

index 203fa14..cd72fa3 100644 (file)
@@ -19,46 +19,171 @@ struct s_queue ttyinq[NUM_DEV_TTY + 1] = { /* ttyinq[0] is never used */
        {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2},
 };
 
-void tty_setup(uint8_t minor, uint8_t flag)
+static tcflag_t uart0_mask[4] = {
+       _ISYS,
+       _OSYS,
+       CSIZE|CSTOPB|PARENB|PARODD|_CSYS,
+       _LSYS
+};
+
+static tcflag_t uart1_mask[4] = {
+       _ISYS,
+       /* FIXME: break */
+       _OSYS,
+       /* FIXME CTS/RTS */
+       CSIZE|CBAUD|CSTOPB|PARENB|PARODD|_CSYS,
+       _LSYS,
+};
+
+tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
+       NULL,
+       uart0_mask,
+       uart1_mask
+};
+
+uint8_t sio_r[] = {
+       0x03, 0xC1,
+       0x04, 0xC4,
+       0x05, 0xEA
+};
+
+static void sio2_setup(uint8_t minor, uint8_t flags)
 {
-       if (minor == 1) {
+       struct termios *t = &ttydata[minor].termios;
+       uint8_t r;
+       /* Set bits per character */
+       sio_r[1] = 0x01 | ((t->c_cflag & CSIZE) << 2);
+       r = 0xC4;
+       if (t->c_cflag & CSTOPB)
+               r |= 0x08;
+       if (t->c_cflag & PARENB)
+               r |= 0x01;
+       if (t->c_cflag & PARODD)
+               r |= 0x02;
+       sio_r[3] = r;
+       sio_r[5] = 0x8A | ((t->c_cflag & CSIZE) << 1);
+}
+
+void tty_setup(uint8_t minor, uint8_t flags)
+{
+       if (ser_type == 1) {
+               sio2_setup(minor, flags);
+               sio2_otir(SIO0_BASE + 2 * minor);
+               /* We need to do CTS/RTS support and baud setting on channel 2
+                  yet */
+       }
+       if (ser_type == 2) {
+               struct termios *t = &ttydata[1].termios;
+               uint8_t r = t->c_cflag & CSIZE;
+               /* No CS5/CS6 CS7 must have parity enabled */
+               if (r <= CS7) {
+                       t->c_cflag &= ~CSIZE;
+                       t->c_cflag |= CS7|PARENB;
+               }
+               /* No CS8 parity and 2 stop bits */
+               if (r == CS8 && (t->c_cflag & PARENB))
+                       t->c_cflag &= ~CSTOPB;
+               /* There is no obvious logic to this */
+               switch(t->c_cflag & (CSIZE|PARENB|PARODD|CSTOPB)) {
+               case CS7|PARENB:
+                       r = 0xEB;
+                       break;
+               case CS7|PARENB|PARODD:
+                       r = 0xEF;
+                       break;
+               case CS7|PARENB|CSTOPB:
+                       r = 0xE3;
+               case CS7|PARENB|PARODD|CSTOPB:
+                       r = 0xE7;
+               case CS8|CSTOPB:
+                       r = 0xF3;
+                       break;
+               case CS8:
+                       r = 0xF7;
+                       break;
+               case CS8|PARENB:
+                       r = 0xFB;
+                       break;
+               case CS8|PARENB|PARODD:
+                       r = 0xFF;
+                       break;
+               }
+               ACIA_C = r;
        }
 }
 
 int tty_carrier(uint8_t minor)
 {
-//      uint8_t c;
-       if (minor == 1) {
-//              c = UART0_MSR;
-//              return (c & 0x80) ? 1 : 0; /* test DCD */
-       }
-       return 1;
+        uint8_t c;
+       if (ser_type == 1) {
+               if (minor == 1) {
+                       SIOA_C = 0;
+                       c = SIOA_C;
+               } else {
+                       SIOB_C = 0;
+                       c = SIOB_C;
+               }
+               if (c & 0x8)
+                       return 1;
+               return 0;
+       } else  /* ACIA isn't wired for carrier on any board */
+               return 1;
 }
 
 void tty_pollirq_sio(void)
 {
+       static uint8_t old_ca, old_cb;
        uint8_t ca, cb;
+       uint8_t progress;
+
+       /* Check for an interrupt */
+       SIOA_C = 0;
+       if (!(SIOA_C & 2))
+               return;
 
        /* FIXME: need to process error/event interrupts as we can get
           spurious characters or lines on an unused SIO floating */
-       /* In the true poll case we also need to deal with fake reti as we
-          won't actually reti */
-       SIOA_C = 0;             // read register 0
-       ca = SIOA_C;
-       if (ca & 1)
-               tty_inproc(1, SIOA_D);
-       if (ca & 4) {
-               tty_outproc(1);
-               SIOA_C = 5 << 3;        // reg 0 CMD 5 - reset transmit interrupt pending
-       }
-       SIOB_C = 0;             // read register 0
-       cb = SIOB_C;
-       if (cb & 1)
-               tty_inproc(2, SIOB_D);
-       if (cb & 4) {
-               tty_outproc(2);
-               SIOB_C = 5 << 3;        // reg 0 CMD 5 - reset transmit interrupt pending
-       }
+       do {
+               progress = 0;
+               SIOA_C = 0;             // read register 0
+               ca = SIOA_C;
+               /* Input pending */
+               if ((ca & 1) && !fullq(&ttyinq[1])) {
+                       progress = 1;
+                       tty_inproc(1, SIOA_D);
+               }
+               /* Break */
+               if (ca & 2)
+                       SIOA_C = 2 << 5;
+               /* Output pending */
+               if (ca & 4) {
+                       tty_outproc(1);
+                       SIOA_C = 5 << 3;        // reg 0 CMD 5 - reset transmit interrupt pending
+               }
+               /* Carrier changed */
+               if ((ca ^ old_ca) & 8) {
+                       if (ca & 8)
+                               tty_carrier_raise(1);
+                       else
+                               tty_carrier_drop(1);
+               }
+               SIOB_C = 0;             // read register 0
+               cb = SIOB_C;
+               if ((cb & 1) && !fullq(&ttyinq[2])) {
+                       tty_inproc(2, SIOB_D);
+                       progress = 1;
+               }
+               if (cb & 4) {
+                       tty_outproc(2);
+                       SIOB_C = 5 << 3;        // reg 0 CMD 5 - reset transmit interrupt pending
+               }
+               if ((cb ^ old_cb) & 8) {
+                       if (cb & 8)
+                               tty_carrier_raise(2);
+                       else
+                               tty_carrier_drop(2);
+               }
+       } while(progress);
 }
 
 void tty_pollirq_acia(void)
@@ -102,7 +227,10 @@ void tty_sleeping(uint8_t minor)
    interrupts as we do this. Really we want to switch to irq driven tx ints
    on this platform I think. Need to time it and see
 
-   An asm common level tty driver might be a better idea */
+   An asm common level tty driver might be a better idea
+
+   Need to review this we should be ok as the IRQ handler always leaves
+   us pointing at RR0 */
 ttyready_t tty_writeready(uint8_t minor)
 {
        irqflags_t irq;
index b742988..0dcf1a8 100644 (file)
@@ -28,4 +28,6 @@ __sfr __at (ACIA_BASE + 1) ACIA_D;
 
 extern bool boot_from_rom;
 
+extern void sio2_otir(uint8_t port) __z88dk_fastcall;
+
 #endif
index 2bd1341..b052912 100644 (file)
@@ -388,6 +388,19 @@ _kernel_pages:
 map_savearea:
        .db     0,0,0,0
 
+;
+;      A little SIO helper
+;
+       .globl _sio_r
+       .globl _sio2_otir
+
+_sio2_otir:
+       ld b,#0x06
+       ld c,l
+       ld hl,#_sio_r
+       otir
+       ret
+
 ;=========================================================================
 ; Basic console I/O
 ;=========================================================================