sc108: flesh out all the serial support
authorAlan Cox <alan@linux.intel.com>
Mon, 1 Oct 2018 21:53:35 +0000 (22:53 +0100)
committerAlan Cox <alan@linux.intel.com>
Mon, 1 Oct 2018 21:53:35 +0000 (22:53 +0100)
We still don't support full RTS/CTS but really the I/O paths for SIO handling
need to be rewritten to fast asm helpers anyway.

Kernel/platform-sc108/devtty.c
Kernel/platform-sc108/rc2014.h
Kernel/platform-sc108/sc108.s

index c60736f..3f2f6da 100644 (file)
@@ -11,52 +11,177 @@ char tbuf2[TTYSIZ];
 
 uint8_t ser_type = 2;
 
+tcflag_t uart0_mask[4] = {
+       _ISYS,
+       _OSYS,
+       CSIZE|CSTOPB|PARENB|PARODD|_CSYS,
+       _LSYS
+};
+
+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
+};
+
 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},
        {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2},
 };
 
+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 bord */
+               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)
index fffce86..21ee491 100644 (file)
@@ -20,4 +20,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 fd639b3..e6bb0e5 100644 (file)
@@ -1,42 +1,42 @@
 ;
-;          SC108 Initial Support
+;      SC108 Initial Support
 ;
 
-            .module sc108
-
-            ; exported symbols
-            .globl init_hardware
-            .globl interrupt_handler
-            .globl _program_vectors
-           .globl _kernel_flag
-           .globl map_page_low
-           .globl map_kernel_low
-           .globl map_user_low
-           .globl map_save_low
-           .globl map_restore_low
-           .globl _platform_doexec
-           .globl _platform_reboot
-           .globl _int_disabled
-
-            ; exported debugging tools
-            .globl _platform_monitor
-            .globl outchar
-
-            ; imported symbols
-            .globl _ramsize
-            .globl _procmem
-            .globl istack_top
-            .globl istack_switched_sp
-           .globl kstack_top
-            .globl unix_syscall_entry
-            .globl outcharhex
-           .globl _ser_type
-
-           .globl s__COMMONMEM
-           .globl l__COMMONMEM
-
-            .include "kernel.def"
-            .include "../kernel.def"
+        .module sc108
+
+        ; exported symbols
+        .globl init_hardware
+        .globl interrupt_handler
+        .globl _program_vectors
+       .globl _kernel_flag
+       .globl map_page_low
+       .globl map_kernel_low
+       .globl map_user_low
+       .globl map_save_low
+       .globl map_restore_low
+       .globl _platform_doexec
+       .globl _platform_reboot
+       .globl _int_disabled
+
+        ; exported debugging tools
+        .globl _platform_monitor
+        .globl outchar
+
+        ; imported symbols
+        .globl _ramsize
+        .globl _procmem
+        .globl istack_top
+        .globl istack_switched_sp
+       .globl kstack_top
+        .globl unix_syscall_entry
+        .globl outcharhex
+       .globl _ser_type
+
+       .globl s__COMMONMEM
+       .globl l__COMMONMEM
+
+        .include "kernel.def"
+        .include "../kernel.def"
 
 
 ;
 ; so we can recover the discard memory into the buffer pool
 ;
 
-           .globl _bufpool
-           .area _BUFFERS
+       .globl _bufpool
+       .area _BUFFERS
 
 _bufpool:
-           .ds BUFSIZE * NBUFS
+       .ds BUFSIZE * NBUFS
 
 ; -----------------------------------------------------------------------------
 ;
@@ -56,17 +56,17 @@ _bufpool:
 ;      usual Z80 setup.
 ;
 ; -----------------------------------------------------------------------------
-            .area _COMMONMEM
+        .area _COMMONMEM
 
 _platform_monitor:
            ; Reboot ends up back in the monitor
 _platform_reboot:
-           xor a
-           out (0x38), a               ; ROM appears low
-           rst 0                       ; bang
+       xor a
+       out (0x38), a           ; ROM appears low
+       rst 0                   ; bang
 
 _int_disabled:
-           .db 1
+       .db 1
 
 ; -----------------------------------------------------------------------------
 ;
@@ -76,7 +76,7 @@ _int_disabled:
 ; -----------------------------------------------------------------------------
 
 banknum:
-           .byte 0x81          ; copied into far bank then set to 1
+       .byte 0x81              ; copied into far bank then set to 1
 
 ; -----------------------------------------------------------------------------
 ;      All of discard gets reclaimed when init is run
@@ -84,135 +84,112 @@ banknum:
 ;      Discard must be above 0x8000 as we need some of it when the ROM
 ;      is paged in during init_hardware
 ; -----------------------------------------------------------------------------
-            .area _DISCARD
+       .area _DISCARD
 
 init_hardware:
-            ld hl, #128
-            ld (_ramsize), hl
-           ld hl,#64
-            ld (_procmem), hl
-
-           ld hl,#s__COMMONMEM
-           ld ix,#s__COMMONMEM
-           ld bc,#l__COMMONMEM
-           xor a                       ; Kernel + ROM
-           out (0x38),a                ; 
-
-           ld de,#0x8000               ; bank 0 to bank 1 (ROM in)
-           xor a                       ; return to bank 0
-           call 0x7FFD                 ; ROM helper vector
-
-           ld a,#0x01                  ; bank 0 ROM out
-           out (0x38),a
-           ld (banknum),a              ; and correct page
-
-           ; We now have our common in place. We can do the rest ourselves
-
-           ; Put the low stubs into place in the kernel
-           ld hl,#stubs_low
-           ld de,#0
-           ld bc,#0x68
-           ldir
-           ld hl,#stubs_low
-           ld ix,#0
-           ld bc,#0x68
-           call ldir_to_user
-
-           ; Play guess the serial port
-           ld bc,#0x80
-           ; If writing to 0x80 changes the data we see on an input then
-           ; it's most likely an SIO and not the 68B50
-           out (c),b
-           in d,(c)
-           inc b
-           out (c),b
-           in a,(c)
-           sub d
-;;FIXME        jr z, is_sio
-
-           ; We have however pooped on the 68B50 setup so put it back into
-           ; a sensible state.
-           ld a,#0x03
-           out (c),a
-           in a,(c)
-           or a
-           jr z, not_acia_either
-            ld a, #ACIA_RTS_LOW_A
-            out (c),a                  ; Initialise ACIA
-           ld a,#2
-           ld (_ser_type),a
-           im 1
-           ret
-
-           ;
-           ; Doomed I say .... doomed, we're all doomed
-           ;
-           ; At least until RC2014 grows a nice keyboard/display card!
-           ;
+       ld hl, #128
+        ld (_ramsize), hl
+       ld hl,#64
+        ld (_procmem), hl
+
+       ld hl,#s__COMMONMEM
+       ld ix,#s__COMMONMEM
+       ld bc,#l__COMMONMEM
+       xor a                   ; Kernel + ROM
+       out (0x38),a            ;
+
+       ld de,#0x8000           ; bank 0 to bank 1 (ROM in)
+       xor a                   ; return to bank 0
+       call 0x7FFD             ; ROM helper vector
+
+       ld a,#0x01              ; bank 0 ROM out
+       out (0x38),a
+       ld (banknum),a          ; and correct page
+
+       ; We now have our common in place. We can do the rest ourselves
+
+       ; Put the low stubs into place in the kernel
+       ld hl,#stubs_low
+       ld de,#0
+       ld bc,#0x68
+       ldir
+       ld hl,#stubs_low
+       ld ix,#0
+       ld bc,#0x68
+       call ldir_to_user
+
+       ; Play guess the serial port
+       ; This needs doing better. We might be fooled by floating flow
+       ; control lines as the SC104 does expose flow control. FIXME
+       in a,(SIOA_C)
+       and #0x2C
+       cp #0x2C
+       ; CTS and DCD should be high as they are not wired
+       jr nz, try_acia
+
+       ; Repeat the check on SIO B
+       in a,(SIOB_C)
+       and #0x2C
+       cp #0x2C
+       jr z, is_sio
+try_acia:
+       ;
+       ;       Look for an ACIA
+       ;
+       ld a,#ACIA_RESET
+       out (ACIA_C),a
+       ; TX should now have gone
+       in a,(ACIA_C)
+       bit 1,a
+       jr z, not_acia_either
+       ;       Set up the ACIA
+
+        ld a, #ACIA_RTS_LOW_A
+        out (ACIA_C),a                         ; Initialise ACIA
+       ld a,#2
+       ld (_ser_type),a
+       jp serial_up
+
+       ;
+       ; Doomed I say .... doomed, we're all doomed
+       ;
+       ; At least until RC2014 grows a nice keyboard/display card!
+       ;
 not_acia_either:
-           xor a
-           ld (_ser_type),a
-           ret
-
-is_sio:           ld a,b
-          ld (_ser_type),a
-
-init_partial_uart:
-            ld a,#0x00
-            out (SIOA_C),a
-            ld a,#0x18
-            out (SIOA_C),a
-
-            ld a,#0x04
-            out (SIOA_C),a
-            ld a,#0xC4
-            out (SIOA_C),a
-
-            ld a,#0x01
-            out (SIOA_C),a
-            ld a,#0x18;A?          ; Receive int mode 11, tx int enable (was $18)
-            out (SIOA_C),a
-
-            ld a,#0x03
-            out (SIOA_C),a
-            ld a,#0xE1
-            out (SIOA_C),a
-
-RTS_LOW                .EQU    0xEA
-
-            ld a,#0x05
-            out (SIOA_C),a
-            ld a,#RTS_LOW
-            out (SIOA_C),a
-
-            ld a,#0x00
-            out (SIOB_C),a
-            ld a,#0x18
-            out (SIOB_C),a
-
-            ld a,#0x04
-            out (SIOB_C),a
-            ld a,#0xC4
-            out (SIOB_C),a
-
-            ld a,#0x01
-            out (SIOB_C),a
-            ld a, #0x18;A?          ; Receive int mode 11, tx int enable (was $18)
-            out (SIOB_C),a
-
-            ld a,#0x03
-            out (SIOB_C),a
-            ld a,#0xE1
-            out (SIOB_C),a
-
-            ld a,#0x05
-            out (SIOB_C),a
-            ld a,#RTS_LOW
-            out (SIOB_C),a
-
-            im 1 ; set CPU interrupt mode
+       xor a
+       ld (_ser_type),a
+       jp serial_up
+;
+;      We have an SIO so do the required SIO hdance
+;
+is_sio:        ld a,b
+       ld (_ser_type),a
+
+       ld hl,#sio_setup
+       ld bc,#0xA00 + SIOA_C           ; 10 bytes to SIOA_C
+       otir
+       ld hl,#sio_setup
+       ld bc,#0x0A00 + SIOB_C          ; and to SIOB_C
+       otir
+
+serial_up:
+        im 1 ; set CPU interrupt mode
+        ret
+
+RTS_LOW        .EQU    0xEA
+
+sio_setup:
+       .byte 0x00
+       .byte 0x18              ; Reset
+       .byte 0x04
+       .byte 0xC4
+       .byte 0x01
+       .byte 0x18
+       .byte 0x03
+       .byte 0xE1
+       .byte 0x05
+       .byte RTS_LOW
 
-            ret
 
 ;
 ;      Our memory setup is weird and common is kind of meaningless here
@@ -230,6 +207,19 @@ map_page_low:
 
 _program_vectors:
            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
 ;
 ; outchar: Wait for UART TX idle, then print the char in A
 ; destroys: AF