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

index b5ff0f6..e73e2c6 100644 (file)
@@ -17,46 +17,171 @@ struct s_queue ttyinq[NUM_DEV_TTY + 1] = { /* ttyinq[0] is never used */
        {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2},
 };
 
+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)
+{
+       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 (minor == 1) {
+       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 */
        do {
+               progress = 0;
                SIOA_C = 0;             // read register 0
                ca = SIOA_C;
-               if (ca & 1)
+               /* 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)
+               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
                }
-       } while((ca | cb) & 1);
+               if ((cb ^ old_cb) & 8) {
+                       if (cb & 8)
+                               tty_carrier_raise(2);
+                       else
+                               tty_carrier_drop(2);
+               }
+       } while(progress);
 }
 
 void tty_pollirq_acia(void)
@@ -95,7 +220,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 2cf8404..d7cb624 100644 (file)
@@ -18,4 +18,6 @@ __sfr __at (SIO0_BASE + 3) SIOB_D;
 __sfr __at (ACIA_BASE + 0) ACIA_C;
 __sfr __at (ACIA_BASE + 1) ACIA_D;
 
+extern void sio2_otir(uint8_t port) __z88dk_fastcall;
+
 #endif
index 50182d4..9ff1273 100644 (file)
@@ -357,6 +357,20 @@ map_save_kernel:
        pop af
        ret
 
+;
+;      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
 ;=========================================================================