AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
uart.c
Go to the documentation of this file.
1
11
12#include <core/system.h>
13#include <dev/dev.h>
14#include <dev/tty.h>
15#include <dev/uart.h>
16#include <fs/posix.h>
17#include <ds/queue.h>
18#include <ds/ringbuf.h>
19#include <sys/sched.h>
20
21#define UART_BUF 64
22
23/* each ring's size: it must hold a full line from the terminal
24 * (TTY_BUF_SIZE), like the pseudo-terminals' rings */
25#define UART_RING 4096
26static struct uart *devices[192] = {0}; /* the registered UARTs, by number */
27
35void uart_receive_handler(struct uart *u, size_t size)
36{
37 char buf[UART_BUF];
38
39 /* take them a buffer at a time */
40 while (size) {
41 size_t n = MIN(size, sizeof(buf));
42
43 for (size_t i = 0; i < n; ++i)
44 buf[i] = u->receive(u);
45
46 tty_master_write(u->tty, n, buf);
47 size -= n;
48 }
49
51}
52
59void uart_transmit_handler(struct uart *u, size_t size)
60{
61 size_t len = ringbuf_available(u->out);
62 len = MIN(size, len);
63
64 for (size_t i = 0; i < len; ++i) {
65 char c = 0;
66 ringbuf_read(u->out, 1, &c);
67 u->transmit(u, c);
68 }
69
71}
72
82ssize_t uart_master_write(struct tty *tty, size_t size, void *buf)
83{
84 struct uart *u = (struct uart *) tty->p;
85 size_t s = ringbuf_write(u->out, size, buf);
87 return s;
88}
89
91static void uart_input_flush(struct tty *tty)
92{
93 struct uart *u = (struct uart *) tty->p;
94 char c;
95
96 while (ringbuf_read(u->in, 1, &c))
97 ;
98}
99
109ssize_t uart_slave_write(struct tty *tty, size_t size, void *buf)
110{
111 struct uart *u = (struct uart *) tty->p;
112 return ringbuf_write(u->in, size, buf);
113}
114
115#define UART_MAX 192
116
120static struct uart *uart_get(devid_t minor)
121{
122#ifndef CONFIG_DEV_CONSOLE
123 /* no virtual terminals: /dev/console (5, 1) is the first UART */
124 if (minor == 1)
125 minor = 64;
126#endif
127
128 if (minor < 64 || minor - 64 >= UART_MAX)
129 return NULL;
130
131 return devices[minor - 64];
132}
133
143ssize_t uart_read(struct devid *dd, off_t offset __unused, struct iobuf *io)
144{
145 struct uart *u = uart_get(dd->minor);
146 if (!u) return -EIO;
147
148 int err = tty_background(u->tty, SIGTTIN);
149 if (err) return err;
150
151 return ringbuf_read_iobuf(u->in, io->resid, io);
152}
153
163ssize_t uart_write(struct devid *dd, off_t offset __unused, struct iobuf *io)
164{
165 struct uart *u = uart_get(dd->minor);
166 if (!u) return -EIO;
167
168 if (u->tty->tios.c_lflag & TOSTOP) {
169 int err = tty_background(u->tty, SIGTTOU);
170
171 if (err)
172 return err;
173 }
174
175 return tty_write_iobuf(u->tty, io, tty_slave_write);
176}
177
180static int uart_file_eof(struct file *file)
181{
182 struct uart *u = uart_get(DEV_MINOR(file->vnode->rdev));
183 return !u || tty_eof(u->tty);
184}
185
189{
190 struct uart *u = uart_get(DEV_MINOR(file->vnode->rdev));
191 return u ? tty_read_timeout(u->tty) : 0;
192}
193
195static int uart_can_read(struct file *file, size_t size)
196{
197 struct uart *u = uart_get(DEV_MINOR(file->vnode->rdev));
198 return !u || tty_can_read(u->tty, ringbuf_available(u->in));
199}
200
209int uart_ioctl(struct devid *dd, int request, void *argp)
210{
211 struct uart *u = uart_get(dd->minor);
212 if (!u) return -EIO;
213 return tty_ioctl(u->tty, request, argp);
214}
215
218static int uart_setup(struct uart *u, struct vnode *vnode)
219{
220 struct ringbuf *in = ringbuf_new(UART_RING), *out = ringbuf_new(UART_RING);
221 struct tty *tty = NULL;
222 int err = -ENOMEM;
223
224 if (!in || !out || (err = tty_new(curproc, 0, uart_master_write, uart_slave_write, u, &tty))) {
225 ringbuf_free(in);
226 ringbuf_free(out);
227 return err;
228 }
229
230 u->init(u);
231 u->in = in;
232 u->out = out;
233
234 /* keep the node it was opened through (/dev/tty opens it): the
235 * interrupts and the terminal outlive that file */
236 u->vnode = vnode;
237 vnode->ref++;
238
239 tty->vnode = vnode;
241 u->tty = tty;
242 return 0;
243}
244
252{
253 struct uart *u = uart_get(DEV_MINOR(file->vnode->rdev));
254 int err;
255
256 if (!u) /* no UART has this minor */
257 return -ENXIO;
258
259 if (!u->tty && (err = uart_setup(u, file->vnode)))
260 return err;
261
262 /* every node of the UART shares the same wait queues */
263 file->vnode->read_queue = &u->read_queue;
264 file->vnode->write_queue = &u->write_queue;
265
266 tty_open(u->tty, file);
267 return 0;
268}
269
278int uart_register(int id, struct uart *u)
279{
280 if (id >= 192)
281 return -EINVAL;
282
283 if (id < 0) { /* the first free number */
284 for (int i = 0; i < 192; ++i) {
285 if (!devices[i]) {
286 devices[i] = u;
287 id = i;
288 goto done;
289 }
290 }
291
292 return -ENOSPC; /* every minor taken */
293 }
294
295done:
296 devices[id] = u;
297
298 printk("uart: registered uart %d: %s\n", id, u->name);
299 return id;
300}
301
302struct dev uart = {
303 .name = "uart",
304
305 .read = uart_read,
306 .write = uart_write,
307 .ioctl = uart_ioctl,
308
309 .fops = {
310 .open = uart_file_open,
311 .read = posix_file_read,
312 .write = posix_file_write,
313 .ioctl = posix_file_ioctl,
314
315 .can_read = uart_can_read,
316 .can_write = __vfs_can_always, /* a writer never waits */
317 .eof = uart_file_eof,
318 .read_timeout = uart_read_timeout,
319 },
320};
static int uart_file_eof(struct file *file)
Returns whether a read that found no data is at the end of the file (the terminal says,...
Definition uart.c:180
int uart_file_open(struct file *file)
Opens a UART's device, setting the UART up the first time.
Definition uart.c:251
ssize_t uart_slave_write(struct tty *tty, size_t size, void *buf)
Takes the terminal's input, after its line editing, for the readers of the UART's device.
Definition uart.c:109
#define UART_MAX
Definition uart.c:115
ssize_t uart_master_write(struct tty *tty, size_t size, void *buf)
Takes the terminal's output, and sends it to the UART at once: the UART drivers don't use a "transmit...
Definition uart.c:82
void uart_transmit_handler(struct uart *u, size_t size)
Sends characters that the terminal output to its UART.
Definition uart.c:59
static void uart_input_flush(struct tty *tty)
Drops the input waiting to be read (tcflush()).
Definition uart.c:91
static int uart_setup(struct uart *u, struct vnode *vnode)
Sets a UART up the first time it is opened: its rings, its terminal, and the UART itself.
Definition uart.c:218
ssize_t uart_read(struct devid *dd, off_t offset, struct iobuf *io)
Reads a UART's terminal.
Definition uart.c:143
static uint64_t uart_read_timeout(struct file *file)
Returns how long a read may wait for data, from the terminal's mode (VTIME), or 0 for no limit.
Definition uart.c:188
static struct uart * devices[192]
Definition uart.c:26
static int uart_can_read(struct file *file, size_t size)
Returns whether a read wouldn't have to wait.
Definition uart.c:195
static struct uart * uart_get(devid_t minor)
Returns the UART of a minor (they start at 64), or NULL if there's none.
Definition uart.c:120
int uart_register(int id, struct uart *u)
Registers a UART, as /dev/ttyS<id>.
Definition uart.c:278
#define UART_BUF
Definition uart.c:21
int uart_ioctl(struct devid *dd, int request, void *argp)
Handles a UART terminal's ioctl()s, which are the terminal's.
Definition uart.c:209
void uart_receive_handler(struct uart *u, size_t size)
Takes characters a UART received, and gives them to its terminal.
Definition uart.c:35
ssize_t uart_write(struct devid *dd, off_t offset, struct iobuf *io)
Writes to a UART's terminal.
Definition uart.c:163
#define UART_RING
Definition uart.c:25
#define DEV_MINOR(dev)
Definition dev.h:78
ssize_t tty_slave_write(struct tty *tty, size_t size, void *_buf)
Takes what programs write to the terminal, and sends it to the device through output processing (OPOS...
Definition generic.c:297
int tty_ioctl(struct tty *tty, int request, void *argp)
Handles a terminal's ioctl()s: its modes (TCGETS, TCSETS, ...), flushing, its session and foreground ...
Definition generic.c:455
ssize_t tty_write_iobuf(struct tty *tty, struct iobuf *io, ttyio write)
Writes to a terminal from an iobuf (user memory), to either side: a piece at a time through a kernel ...
Definition generic.c:408
int tty_new(struct proc *proc, size_t buf_size, ttyio master, ttyio slave, void *p, struct tty **ref)
Makes a new terminal, with the default modes (canonical, echo, signals, ICRNL, IXON,...
Definition generic.c:584
ssize_t tty_master_write(struct tty *tty, size_t size, void *buf)
Takes input from the terminal's device (the keyboard, a UART, or a pseudo-terminal's master),...
Definition generic.c:111
int tty_can_read(struct tty *tty, size_t buffered)
Says whether the terminal is readable, for select() and poll(): there is input, or an end-of-file.
Definition generic.c:240
int tty_eof(struct tty *tty)
Says whether a read that found nothing to return should return 0 at once: at an end-of-file (VEOF at ...
Definition generic.c:200
int tty_background(struct tty *tty, int sig)
Stops a background process that reads the terminal, writes it or changes it: if the current process i...
Definition generic.c:259
uint64_t tty_read_timeout(struct tty *tty)
Says how long a read waits for input: VTIME tenths of a second with VMIN 0 in non-canonical mode,...
Definition generic.c:221
void tty_open(struct tty *tty, struct file *file)
Handles a terminal device being opened: it becomes the controlling terminal of a session leader that ...
Definition generic.c:646
#define MIN(a, b)
Definition system.h:11
int posix_file_ioctl(struct file *file, int request, void *argp)
Passes an ioctl() request on to the file's vnode (a device's, or its filesystem's).
Definition ioctl.c:19
ssize_t posix_file_read(struct file *file, struct iobuf *io)
Reads from an open file at its offset, and moves the offset past what was read.
Definition read.c:29
ssize_t posix_file_write(struct file *file, struct iobuf *io)
Writes to an open file at its offset, and moves the offset past what was written.
Definition write.c:25
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
#define curproc
Definition sched.h:13
#define NULL
Definition stddef.h:27
unsigned long long int uint64_t
Definition stddef.h:23
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
Which device: its kind (S_IFCHR or S_IFBLK) and numbers.
Definition dev.h:21
devid_t minor
Definition dev.h:24
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
An iobuf.
Definition iobuf.h:35
size_t resid
Definition iobuf.h:38
A ring buffer.
Definition ringbuf.h:18
A terminal, and its line discipline's state.
Definition tty.h:25
struct termios tios
Definition tty.h:45
void * p
the device's own data
Definition tty.h:71
struct vnode * vnode
the device's vnode, which /dev/tty opens in its place
Definition tty.h:66
void(*) input_flush(struct tty *tty)
discards the input that readers haven't read yet
Definition tty.h:80
A serial port.
Definition uart.h:17
struct vnode * vnode
Definition uart.h:24
char * name
Definition uart.h:18
struct waitq read_queue
Definition uart.h:28
ssize_t(*) transmit(struct uart *u, char c)
Definition uart.h:32
void(*) init(struct uart *u)
Definition uart.h:31
char(*) receive(struct uart *u)
Definition uart.h:33
struct ringbuf * in
Definition uart.h:20
struct ringbuf * out
Definition uart.h:21
struct waitq write_queue
Definition uart.h:29
struct tty * tty
Definition uart.h:23
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
size_t ref
how many references there are to it
Definition vfs.h:133
uint8_t devid_t
Definition types.h:17
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10
void waitq_wakeup(struct waitq *waitq)
Wakes up every thread sleeping on a wait queue, and every thread polling it.
Definition waitq.c:178