From: Alan Cox Date: Tue, 2 Oct 2018 11:44:54 +0000 (+0100) Subject: rc2014: add all the tty setup support X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=7d003304924c7ac5ef499ca0fa9262d1a8f85a4e;p=FUZIX.git rc2014: add all the tty setup support --- diff --git a/Kernel/platform-rc2014/devtty.c b/Kernel/platform-rc2014/devtty.c index 203fa144..cd72fa39 100644 --- a/Kernel/platform-rc2014/devtty.c +++ b/Kernel/platform-rc2014/devtty.c @@ -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; diff --git a/Kernel/platform-rc2014/rc2014.h b/Kernel/platform-rc2014/rc2014.h index b7429886..0dcf1a8e 100644 --- a/Kernel/platform-rc2014/rc2014.h +++ b/Kernel/platform-rc2014/rc2014.h @@ -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 diff --git a/Kernel/platform-rc2014/rc2014.s b/Kernel/platform-rc2014/rc2014.s index 2bd13413..b052912b 100644 --- a/Kernel/platform-rc2014/rc2014.s +++ b/Kernel/platform-rc2014/rc2014.s @@ -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 ;=========================================================================