Skip to content

Commit 44fdd8e

Browse files
authored
Merge pull request #234 from smartobjectoriented/232-rework-console
rework console to support simple cannon and raw mode
2 parents 1e32feb + 8452e8f commit 44fdd8e

File tree

3 files changed

+310
-7
lines changed

3 files changed

+310
-7
lines changed

so3/devices/console.c

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,77 @@
1616
*
1717
*/
1818

19+
#include <termios.h>
1920
#include <device/serial.h>
2021

22+
/* Default termios flags that will be used by the console. */
23+
static termios_t termios = {
24+
.c_iflag = INLCR,
25+
.c_lflag = ECHO | ICANON,
26+
};
27+
28+
static int console_write(int fd, const void *buffer, int count);
29+
30+
static char console_get_next_c(void)
31+
{
32+
char c = serial_getc();
33+
34+
/* Convert CR to LF if required */
35+
if (termios.c_iflag & INLCR) {
36+
if (c == '\r')
37+
c = '\n';
38+
}
39+
40+
return c;
41+
}
42+
43+
static void icanon_handle_char(int fd, char c, char *buf, size_t *total)
44+
{
45+
/* Backspace handle */
46+
if (c == 127) {
47+
if (*total != 0) {
48+
/* Delete last char from console and buffer */
49+
buf[*total] = '\0';
50+
(*total)--;
51+
52+
if (termios.c_lflag & ECHO)
53+
console_write(fd, "\b \b", 3);
54+
}
55+
56+
return;
57+
}
58+
59+
/* Generic handle */
60+
buf[*total] = c;
61+
(*total)++;
62+
63+
if (termios.c_lflag & ECHO)
64+
console_write(fd, &c, 1);
65+
}
66+
2167
/* Used to read from a serial (uart) console. We report only one byte when the byte is ready. */
22-
static int console_getc(int gfd, void *buffer, int count)
68+
static int console_getc(int fd, void *buffer, int count)
2369
{
24-
/* Read one byte from the UART console */
25-
*((uint8_t *) buffer) = serial_getc();
70+
char c;
71+
char *c_buf = (char *) buffer;
72+
size_t total = 0;
2673

27-
return 1;
74+
if (termios.c_lflag & ICANON) {
75+
do {
76+
/* Read and handle next byte */
77+
c = console_get_next_c();
78+
icanon_handle_char(fd, c, c_buf, &total);
79+
} while (c != '\n' && total < count);
80+
} else {
81+
*c_buf = console_get_next_c();
82+
total = 1;
83+
}
84+
85+
return total;
2886
}
2987

3088
/* Send out to the serial console. */
31-
static int console_write(int gfd, const void *buffer, int count)
89+
static int console_write(int fd, const void *buffer, int count)
3290
{
3391
int ret;
3492

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

45103
switch (cmd) {
104+
case TCGETS:
105+
*(struct termios *) args = termios;
106+
rc = 0;
107+
break;
108+
109+
case TCSETS:
110+
case TCSETSW:
111+
case TCSETSF:
112+
/* We should normally wait for all output to be trasmitted
113+
and flush input depending on the IOCTL. But we will assumed
114+
this will already by ok for now. */
115+
termios = *(struct termios *) args;
116+
rc = 0;
117+
break;
118+
46119
case TIOCGWINSZ:
47120
rc = serial_gwinsize((struct winsize *) args);
48121
break;

so3/include/termios.h

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+
3+
/* Copied from Linux:
4+
* - include/uapi/asm-generic/ioctls.h
5+
* - include/uapi/asm-generic/termbits.h
6+
* - include/uapi/asm-generic/termbits-common.h
7+
*/
8+
9+
#ifndef TERMIOS_H
10+
#define TERMIOS_H
11+
12+
/* clang-format off */
13+
14+
/* IOCTL for termios management */
15+
#define TCGETS 0x5401
16+
#define TCSETS 0x5402
17+
#define TCSETSW 0x5403
18+
#define TCSETSF 0x5404
19+
20+
#define NCCS 19
21+
22+
typedef unsigned char cc_t;
23+
typedef unsigned int speed_t;
24+
typedef unsigned int tcflag_t;
25+
26+
typedef struct termios {
27+
tcflag_t c_iflag;
28+
tcflag_t c_oflag;
29+
tcflag_t c_cflag;
30+
tcflag_t c_lflag;
31+
cc_t c_line;
32+
cc_t c_cc[NCCS];
33+
speed_t __c_ispeed;
34+
speed_t __c_ospeed;
35+
} termios_t;
36+
37+
/* c_cc characters */
38+
#define VINTR 0
39+
#define VQUIT 1
40+
#define VERASE 2
41+
#define VKILL 3
42+
#define VEOF 4
43+
#define VTIME 5
44+
#define VMIN 6
45+
#define VSWTC 7
46+
#define VSTART 8
47+
#define VSTOP 9
48+
#define VSUSP 10
49+
#define VEOL 11
50+
#define VREPRINT 12
51+
#define VDISCARD 13
52+
#define VWERASE 14
53+
#define VLNEXT 15
54+
#define VEOL2 16
55+
56+
/* c_iflag bits */
57+
#define IGNBRK 0x001 /* Ignore break condition */
58+
#define BRKINT 0x002 /* Signal interrupt on break */
59+
#define IGNPAR 0x004 /* Ignore characters with parity errors */
60+
#define PARMRK 0x008 /* Mark parity and framing errors */
61+
#define INPCK 0x010 /* Enable input parity check */
62+
#define ISTRIP 0x020 /* Strip 8th bit off characters */
63+
#define INLCR 0x040 /* Map NL to CR on input */
64+
#define IGNCR 0x080 /* Ignore CR */
65+
#define ICRNL 0x100 /* Map CR to NL on input */
66+
#define IXANY 0x800 /* Any character will restart after stop */
67+
#define IUCLC 0x0200
68+
#define IXON 0x0400
69+
#define IXOFF 0x1000
70+
#define IMAXBEL 0x2000
71+
#define IUTF8 0x4000
72+
73+
/* c_oflag bits */
74+
#define OPOST 0x01 /* Perform output processing */
75+
#define OCRNL 0x08
76+
#define ONOCR 0x10
77+
#define ONLRET 0x20
78+
#define OFILL 0x40
79+
#define OFDEL 0x80
80+
#define OLCUC 0x00002
81+
#define ONLCR 0x00004
82+
#define NLDLY 0x00100
83+
#define NL0 0x00000
84+
#define NL1 0x00100
85+
#define CRDLY 0x00600
86+
#define CR0 0x00000
87+
#define CR1 0x00200
88+
#define CR2 0x00400
89+
#define CR3 0x00600
90+
#define TABDLY 0x01800
91+
#define TAB0 0x00000
92+
#define TAB1 0x00800
93+
#define TAB2 0x01000
94+
#define TAB3 0x01800
95+
#define XTABS 0x01800
96+
#define BSDLY 0x02000
97+
#define BS0 0x00000
98+
#define BS1 0x02000
99+
#define VTDLY 0x04000
100+
#define VT0 0x00000
101+
#define VT1 0x04000
102+
#define FFDLY 0x08000
103+
#define FF0 0x00000
104+
#define FF1 0x08000
105+
106+
/* c_cflag bit meaning */
107+
/* Common CBAUD rates */
108+
#define B0 0x00000000 /* hang up */
109+
#define B50 0x00000001
110+
#define B75 0x00000002
111+
#define B110 0x00000003
112+
#define B134 0x00000004
113+
#define B150 0x00000005
114+
#define B200 0x00000006
115+
#define B300 0x00000007
116+
#define B600 0x00000008
117+
#define B1200 0x00000009
118+
#define B1800 0x0000000a
119+
#define B2400 0x0000000b
120+
#define B4800 0x0000000c
121+
#define B9600 0x0000000d
122+
#define B19200 0x0000000e
123+
#define B38400 0x0000000f
124+
#define EXTA B19200
125+
#define EXTB B38400
126+
127+
#define CBAUD 0x0000100f
128+
#define CSIZE 0x00000030
129+
#define CS5 0x00000000
130+
#define CS6 0x00000010
131+
#define CS7 0x00000020
132+
#define CS8 0x00000030
133+
#define CSTOPB 0x00000040
134+
#define CREAD 0x00000080
135+
#define PARENB 0x00000100
136+
#define PARODD 0x00000200
137+
#define HUPCL 0x00000400
138+
#define CLOCAL 0x00000800
139+
#define CBAUDEX 0x00001000
140+
#define BOTHER 0x00001000
141+
#define B57600 0x00001001
142+
#define B115200 0x00001002
143+
#define B230400 0x00001003
144+
#define B460800 0x00001004
145+
#define B500000 0x00001005
146+
#define B576000 0x00001006
147+
#define B921600 0x00001007
148+
#define B1000000 0x00001008
149+
#define B1152000 0x00001009
150+
#define B1500000 0x0000100a
151+
#define B2000000 0x0000100b
152+
#define B2500000 0x0000100c
153+
#define B3000000 0x0000100d
154+
#define B3500000 0x0000100e
155+
#define B4000000 0x0000100f
156+
#define CIBAUD 0x100f0000 /* input baud rate */
157+
158+
#define ADDRB 0x20000000 /* address bit */
159+
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
160+
#define CRTSCTS 0x80000000 /* flow control */
161+
162+
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
163+
164+
/* c_lflag bits */
165+
#define ISIG 0x00001
166+
#define ICANON 0x00002
167+
#define XCASE 0x00004
168+
#define ECHO 0x00008
169+
#define ECHOE 0x00010
170+
#define ECHOK 0x00020
171+
#define ECHONL 0x00040
172+
#define NOFLSH 0x00080
173+
#define TOSTOP 0x00100
174+
#define ECHOCTL 0x00200
175+
#define ECHOPRT 0x00400
176+
#define ECHOKE 0x00800
177+
#define FLUSHO 0x01000
178+
#define PENDIN 0x04000
179+
#define IEXTEN 0x08000
180+
#define EXTPROC 0x10000
181+
182+
/* tcflow() ACTION argument and TCXONC use these */
183+
#define TCOOFF 0 /* Suspend output */
184+
#define TCOON 1 /* Restart suspended output */
185+
#define TCIOFF 2 /* Send a STOP character */
186+
#define TCION 3 /* Send a START character */
187+
188+
/* tcflush() QUEUE_SELECTOR argument and TCFLSH use these */
189+
#define TCIFLUSH 0 /* Discard data received but not yet read */
190+
#define TCOFLUSH 1 /* Discard data written but not yet sent */
191+
#define TCIOFLUSH 2 /* Discard all pending data */
192+
193+
/* clang-format on */
194+
195+
#endif // TERMIOS_H

usr/src/more.c

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
#include <fcntl.h>
2323

24+
#include <termios.h>
25+
#include <signal.h>
2426
#include <unistd.h>
2527
#include <syscall.h>
2628
#include <stdio.h>
@@ -32,9 +34,19 @@
3234

3335
char buf[BUFSIZE];
3436
struct winsize wsz;
37+
struct termios old_term;
38+
39+
/* Handler for sigint to restore console flags. */
40+
void sigint_handler(int sig)
41+
{
42+
tcsetattr(STDERR_FILENO, TCSANOW, &old_term);
43+
exit(0);
44+
}
3545

3646
int main(int argc, char **argv)
3747
{
48+
struct termios raw_term;
49+
struct sigaction sa = {};
3850
int quit = 0;
3951
int fd = STDIN_FILENO, nb_bytes, line_max, columns_max;
4052
int cpt_columns = -1, cpt_line = 0;
@@ -53,8 +65,20 @@ int main(int argc, char **argv)
5365
return 2;
5466
}
5567
}
68+
69+
/* Save old console mode */
70+
tcgetattr(STDERR_FILENO, &old_term);
71+
72+
/* Set SIGINT handler to restore the terminal mode correctly */
73+
sa.sa_handler = sigint_handler;
74+
sigaction(SIGINT, &sa, NULL);
75+
76+
/* Set console mode to raw */
77+
cfmakeraw(&raw_term);
78+
tcsetattr(STDERR_FILENO, TCSANOW, &raw_term);
79+
5680
/* Get number of lines and columns */
57-
err = ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsz);
81+
err = ioctl(STDERR_FILENO, TIOCGWINSZ, &wsz);
5882
if (err != 0) {
5983
printf("Errno: %d\n ioctl error %d\n", errno, err);
6084
return 3;
@@ -97,7 +121,16 @@ int main(int argc, char **argv)
97121
printf("\n--MORE--");
98122
fflush(stdout);
99123

100-
key = getc(stderr);
124+
/* Read next char. Don't use getc as it requires
125+
a FILE* and this will result in no actual read
126+
on stderr. stdin isn't available as it can be
127+
an input pipe. */
128+
err = read(STDERR_FILENO, &key, 1);
129+
if (err != 1) {
130+
quit = 1;
131+
break;
132+
}
133+
101134
if ((key == 'q') || (key == 'Q')) {
102135
quit = 1;
103136
break;
@@ -113,5 +146,7 @@ int main(int argc, char **argv)
113146
}
114147
putchar('\n');
115148

149+
tcsetattr(STDERR_FILENO, TCSANOW, &old_term);
150+
116151
return 0;
117152
}

0 commit comments

Comments
 (0)