Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 78 additions & 5 deletions so3/devices/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,77 @@
*
*/

#include <termios.h>
#include <device/serial.h>

/* Default termios flags that will be used by the console. */
static termios_t termios = {
.c_iflag = INLCR,
.c_lflag = ECHO | ICANON,
};

static int console_write(int fd, const void *buffer, int count);

static char console_get_next_c(void)
{
char c = serial_getc();

/* Convert CR to LF if required */
if (termios.c_iflag & INLCR) {
if (c == '\r')
c = '\n';
}

return c;
}

static void icanon_handle_char(int fd, char c, char *buf, size_t *total)
{
/* Backspace handle */
if (c == 127) {
if (*total != 0) {
/* Delete last char from console and buffer */
buf[*total] = '\0';
(*total)--;

if (termios.c_lflag & ECHO)
console_write(fd, "\b \b", 3);
}

return;
}

/* Generic handle */
buf[*total] = c;
(*total)++;

if (termios.c_lflag & ECHO)
console_write(fd, &c, 1);
}

/* Used to read from a serial (uart) console. We report only one byte when the byte is ready. */
static int console_getc(int gfd, void *buffer, int count)
static int console_getc(int fd, void *buffer, int count)
{
/* Read one byte from the UART console */
*((uint8_t *) buffer) = serial_getc();
char c;
char *c_buf = (char *) buffer;
size_t total = 0;

return 1;
if (termios.c_lflag & ICANON) {
do {
/* Read and handle next byte */
c = console_get_next_c();
icanon_handle_char(fd, c, c_buf, &total);
} while (c != '\n' && total < count);
} else {
*c_buf = console_get_next_c();
total = 1;
}

return total;
}

/* Send out to the serial console. */
static int console_write(int gfd, const void *buffer, int count)
static int console_write(int fd, const void *buffer, int count)
{
int ret;

Expand All @@ -43,6 +101,21 @@ static int console_ioctl(int fd, unsigned long cmd, unsigned long args)
int rc;

switch (cmd) {
case TCGETS:
*(struct termios *) args = termios;
rc = 0;
break;

case TCSETS:
case TCSETSW:
case TCSETSF:
/* We should normally wait for all output to be trasmitted
and flush input depending on the IOCTL. But we will assumed
this will already by ok for now. */
termios = *(struct termios *) args;
rc = 0;
break;

case TIOCGWINSZ:
rc = serial_gwinsize((struct winsize *) args);
break;
Expand Down
195 changes: 195 additions & 0 deletions so3/include/termios.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */

/* Copied from Linux:
* - include/uapi/asm-generic/ioctls.h
* - include/uapi/asm-generic/termbits.h
* - include/uapi/asm-generic/termbits-common.h
*/

#ifndef TERMIOS_H
#define TERMIOS_H

/* clang-format off */

/* IOCTL for termios management */
#define TCGETS 0x5401
#define TCSETS 0x5402
#define TCSETSW 0x5403
#define TCSETSF 0x5404

#define NCCS 19

typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;

typedef struct termios {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_line;
cc_t c_cc[NCCS];
speed_t __c_ispeed;
speed_t __c_ospeed;
} termios_t;

/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VTIME 5
#define VMIN 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VEOL 11
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16

/* c_iflag bits */
#define IGNBRK 0x001 /* Ignore break condition */
#define BRKINT 0x002 /* Signal interrupt on break */
#define IGNPAR 0x004 /* Ignore characters with parity errors */
#define PARMRK 0x008 /* Mark parity and framing errors */
#define INPCK 0x010 /* Enable input parity check */
#define ISTRIP 0x020 /* Strip 8th bit off characters */
#define INLCR 0x040 /* Map NL to CR on input */
#define IGNCR 0x080 /* Ignore CR */
#define ICRNL 0x100 /* Map CR to NL on input */
#define IXANY 0x800 /* Any character will restart after stop */
#define IUCLC 0x0200
#define IXON 0x0400
#define IXOFF 0x1000
#define IMAXBEL 0x2000
#define IUTF8 0x4000

/* c_oflag bits */
#define OPOST 0x01 /* Perform output processing */
#define OCRNL 0x08
#define ONOCR 0x10
#define ONLRET 0x20
#define OFILL 0x40
#define OFDEL 0x80
#define OLCUC 0x00002
#define ONLCR 0x00004
#define NLDLY 0x00100
#define NL0 0x00000
#define NL1 0x00100
#define CRDLY 0x00600
#define CR0 0x00000
#define CR1 0x00200
#define CR2 0x00400
#define CR3 0x00600
#define TABDLY 0x01800
#define TAB0 0x00000
#define TAB1 0x00800
#define TAB2 0x01000
#define TAB3 0x01800
#define XTABS 0x01800
#define BSDLY 0x02000
#define BS0 0x00000
#define BS1 0x02000
#define VTDLY 0x04000
#define VT0 0x00000
#define VT1 0x04000
#define FFDLY 0x08000
#define FF0 0x00000
#define FF1 0x08000

/* c_cflag bit meaning */
/* Common CBAUD rates */
#define B0 0x00000000 /* hang up */
#define B50 0x00000001
#define B75 0x00000002
#define B110 0x00000003
#define B134 0x00000004
#define B150 0x00000005
#define B200 0x00000006
#define B300 0x00000007
#define B600 0x00000008
#define B1200 0x00000009
#define B1800 0x0000000a
#define B2400 0x0000000b
#define B4800 0x0000000c
#define B9600 0x0000000d
#define B19200 0x0000000e
#define B38400 0x0000000f
#define EXTA B19200
#define EXTB B38400

#define CBAUD 0x0000100f
#define CSIZE 0x00000030
#define CS5 0x00000000
#define CS6 0x00000010
#define CS7 0x00000020
#define CS8 0x00000030
#define CSTOPB 0x00000040
#define CREAD 0x00000080
#define PARENB 0x00000100
#define PARODD 0x00000200
#define HUPCL 0x00000400
#define CLOCAL 0x00000800
#define CBAUDEX 0x00001000
#define BOTHER 0x00001000
#define B57600 0x00001001
#define B115200 0x00001002
#define B230400 0x00001003
#define B460800 0x00001004
#define B500000 0x00001005
#define B576000 0x00001006
#define B921600 0x00001007
#define B1000000 0x00001008
#define B1152000 0x00001009
#define B1500000 0x0000100a
#define B2000000 0x0000100b
#define B2500000 0x0000100c
#define B3000000 0x0000100d
#define B3500000 0x0000100e
#define B4000000 0x0000100f
#define CIBAUD 0x100f0000 /* input baud rate */

#define ADDRB 0x20000000 /* address bit */
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
#define CRTSCTS 0x80000000 /* flow control */

#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */

/* c_lflag bits */
#define ISIG 0x00001
#define ICANON 0x00002
#define XCASE 0x00004
#define ECHO 0x00008
#define ECHOE 0x00010
#define ECHOK 0x00020
#define ECHONL 0x00040
#define NOFLSH 0x00080
#define TOSTOP 0x00100
#define ECHOCTL 0x00200
#define ECHOPRT 0x00400
#define ECHOKE 0x00800
#define FLUSHO 0x01000
#define PENDIN 0x04000
#define IEXTEN 0x08000
#define EXTPROC 0x10000

/* tcflow() ACTION argument and TCXONC use these */
#define TCOOFF 0 /* Suspend output */
#define TCOON 1 /* Restart suspended output */
#define TCIOFF 2 /* Send a STOP character */
#define TCION 3 /* Send a START character */

/* tcflush() QUEUE_SELECTOR argument and TCFLSH use these */
#define TCIFLUSH 0 /* Discard data received but not yet read */
#define TCOFLUSH 1 /* Discard data written but not yet sent */
#define TCIOFLUSH 2 /* Discard all pending data */

/* clang-format on */

#endif // TERMIOS_H
39 changes: 37 additions & 2 deletions usr/src/more.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

#include <fcntl.h>

#include <termios.h>
#include <signal.h>
#include <unistd.h>
#include <syscall.h>
#include <stdio.h>
Expand All @@ -32,9 +34,19 @@

char buf[BUFSIZE];
struct winsize wsz;
struct termios old_term;

/* Handler for sigint to restore console flags. */
void sigint_handler(int sig)
{
tcsetattr(STDERR_FILENO, TCSANOW, &old_term);
exit(0);
}

int main(int argc, char **argv)
{
struct termios raw_term;
struct sigaction sa = {};
int quit = 0;
int fd = STDIN_FILENO, nb_bytes, line_max, columns_max;
int cpt_columns = -1, cpt_line = 0;
Expand All @@ -53,8 +65,20 @@ int main(int argc, char **argv)
return 2;
}
}

/* Save old console mode */
tcgetattr(STDERR_FILENO, &old_term);

/* Set SIGINT handler to restore the terminal mode correctly */
sa.sa_handler = sigint_handler;
sigaction(SIGINT, &sa, NULL);

/* Set console mode to raw */
cfmakeraw(&raw_term);
tcsetattr(STDERR_FILENO, TCSANOW, &raw_term);

/* Get number of lines and columns */
err = ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsz);
err = ioctl(STDERR_FILENO, TIOCGWINSZ, &wsz);
if (err != 0) {
printf("Errno: %d\n ioctl error %d\n", errno, err);
return 3;
Expand Down Expand Up @@ -97,7 +121,16 @@ int main(int argc, char **argv)
printf("\n--MORE--");
fflush(stdout);

key = getc(stderr);
/* Read next char. Don't use getc as it requires
a FILE* and this will result in no actual read
on stderr. stdin isn't available as it can be
an input pipe. */
err = read(STDERR_FILENO, &key, 1);
if (err != 1) {
quit = 1;
break;
}

if ((key == 'q') || (key == 'Q')) {
quit = 1;
break;
Expand All @@ -113,5 +146,7 @@ int main(int argc, char **argv)
}
putchar('\n');

tcsetattr(STDERR_FILENO, TCSANOW, &old_term);

return 0;
}
Loading