1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
#include "drivers/tty/tty.h"
#include "drivers/chardev.h"
#include "drivers/dev.h"
#include "drivers/keyboard.h"
#include "kernel.h"
#include "mm/kmalloc.h"
#include "util/debug.h"
#include <errno.h>
#ifndef NTERMS
#define NTERMS 3
#endif
ssize_t tty_read(chardev_t *cdev, size_t pos, void *buf, size_t count);
ssize_t tty_write(chardev_t *cdev, size_t pos, const void *buf, size_t count);
chardev_ops_t tty_cdev_ops = {.read = tty_read,
.write = tty_write,
.mmap = NULL,
.fill_pframe = NULL,
.flush_pframe = NULL};
tty_t *ttys[NTERMS] = {NULL};
size_t active_tty;
static void tty_receive_char_multiplexer(uint8_t c);
void tty_init()
{
for (unsigned i = 0; i < NTERMS; i++)
{
tty_t *tty = ttys[i] = kmalloc(sizeof(tty_t));
vterminal_init(&tty->tty_vterminal);
ldisc_init(&tty->tty_ldisc);
tty->tty_cdev.cd_id = MKDEVID(TTY_MAJOR, i);
list_link_init(&tty->tty_cdev.cd_link);
tty->tty_cdev.cd_ops = &tty_cdev_ops;
kmutex_init(&tty->tty_write_mutex);
kmutex_init(&tty->tty_read_mutex);
long ret = chardev_register(&tty->tty_cdev);
KASSERT(!ret);
}
active_tty = 0;
vterminal_make_active(&ttys[active_tty]->tty_vterminal);
KASSERT(ttys[active_tty]);
keyboard_init(tty_receive_char_multiplexer);
}
/**
* Reads from the tty to the buffer.
*
* You should first lock the read mutex of the tty. You should
* then wait until there is something in the line discipline's buffer and only
* read from the ldisc's buffer if there are new characters.
*
* To prevent being preempted, you should set IPL using INTR_KEYBOARD
* correctly and revert it once you are done.
*
* @param cdev the character device that represents tty
* @param pos the position to start reading from; should be ignored
* @param buf the buffer to read into
* @param count the maximum number of bytes to read
* @return the number of bytes actually read into the buffer
*/
ssize_t tty_read(chardev_t *cdev, size_t pos, void *buf, size_t count)
{
// NOT_YET_IMPLEMENTED("DRIVERS: tty_read");
// get the mapped tty
tty_t *tty = cd_to_tty(cdev);
// set the IPL to INTR_KEYBOARD
uint8_t prev_ipl = intr_setipl(INTR_KEYBOARD);
// lock the read mutex of the tty
kmutex_lock(&tty->tty_read_mutex);
dbg(DBG_DISK, "tty_read: before wait_read\n");
// wait until there is something in the line discipline's buffer
ldisc_wait_read(&tty->tty_ldisc);
dbg(DBG_DISK, "tty_read: after wait_read\n");
// read from the ldisc's buffer if there are new characters
ssize_t bytes_read = ldisc_read(&tty->tty_ldisc, buf, count);
// unlock the read mutex of the tty
kmutex_unlock(&tty->tty_read_mutex);
// revert the IPL
intr_setipl(prev_ipl);
return bytes_read;
}
/**
* Writes to the tty from the buffer.
*
* You should first lock the write mutex of the tty. Then you can use
* `vterminal_write` to write to the terminal. Don't forget to use IPL to
* guard this from preemption!
*
* @param cdev the character device that represents tty
* @param pos the position to start reading from; should be ignored
* @param buf the buffer to read from
* @param count the maximum number of bytes to write to the terminal
* @return the number of bytes actually written
*/
ssize_t tty_write(chardev_t *cdev, size_t pos, const void *buf, size_t count)
{
// NOT_YET_IMPLEMENTED("DRIVERS: tty_write");
// get the mapped tty
tty_t *tty = cd_to_tty(cdev);
// set the IPL to INTR_KEYBOARD
uint8_t prev_ipl = intr_setipl(INTR_KEYBOARD);
// lock the write mutex of the tty
kmutex_lock(&tty->tty_write_mutex);
// write to the terminal
size_t bytes_written = vterminal_write(&tty->tty_vterminal, buf, count);
// unlock the write mutex of the tty
kmutex_unlock(&tty->tty_write_mutex);
// revert the IPL
intr_setipl(prev_ipl);
return bytes_written;
}
static void tty_receive_char_multiplexer(uint8_t c)
{
tty_t *tty = ttys[active_tty];
if (c >= F1 && c <= F12)
{
if (c - F1 < NTERMS)
{
/* TODO: this is totally unsafe... Fix it */
active_tty = (unsigned)c - F1;
tty = ttys[active_tty];
vterminal_make_active(&tty->tty_vterminal);
}
return;
}
if (c == CR)
c = LF;
else if (c == DEL)
c = BS;
vterminal_t *vt = &tty->tty_vterminal;
switch ((unsigned)c)
{
case SCROLL_DOWN:
case SCROLL_UP:
// vterminal_scroll(vt, c == SCROLL_DOWN ? 1 : -1);
break;
case SCROLL_DOWN_PAGE:
case SCROLL_UP_PAGE:
// vterminal_scroll(vt, c == SCROLL_DOWN_PAGE ? vt->vt_height :
// -vt->vt_height);
break;
case ESC:
// vterminal_scroll_to_bottom(vt);
break;
default:
ldisc_key_pressed(&tty->tty_ldisc, c);
// vterminal_key_pressed(vt);
break;
}
}
|