2 #include <klibc/string.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/process.h>
6 #include <lunaix/spike.h>
7 #include <lunaix/status.h>
8 #include <lunaix/syslog.h>
10 #include <usr/lunaix/ioctl.h>
14 #define termdev(dev) ((struct term*)(dev)->underlay)
16 #define LCNTL_TABLE_LEN (sizeof(line_controls) / sizeof(struct term_lcntl*))
18 static struct devclass termdev_class = DEVCLASS(LUNAIX, TTY, VTERM);
20 struct device* sysconsole = NULL;
22 extern struct termport_pot_ops default_termport_pot_ops;
25 term_exec_cmd(struct device* dev, u32_t req, va_list args)
27 struct term* term = termdev(dev);
34 pid_t pgid = va_arg(args, pid_t);
44 case TDEV_TCSETCHDEV: {
45 int fd = va_arg(args, int);
48 if (vfs_getfd(fd, &vfd)) {
53 struct device* cdev = resolve_device(vfd->file->inode->data);
58 if (cdev->dev_type != DEV_IFSEQ) {
63 term_bind(term, cdev);
66 case TDEV_TCGETCHDEV: {
67 struct dev_info* devinfo = va_arg(args, struct dev_info*);
75 device_populate_info(term->chdev, devinfo);
79 case TDEV_TCGETATTR: {
80 struct termios* tios = va_arg(args, struct termios*);
81 *tios = (struct termios){.c_oflag = term->oflags,
82 .c_iflag = term->iflags,
83 .c_lflag = term->lflags,
84 .c_cflag = term->cflags};
85 memcpy(tios->c_cc, term->cc, _NCCS * sizeof(cc_t));
86 tios->c_baud = term->iospeed;
88 case TDEV_TCSETATTR: {
89 struct termport_pot_ops* pot_ops;
90 struct termios* tios = va_arg(args, struct termios*);
92 term->iflags = tios->c_iflag;
93 term->oflags = tios->c_oflag;
94 term->lflags = tios->c_lflag;
95 memcpy(term->cc, tios->c_cc, _NCCS * sizeof(cc_t));
97 tcflag_t old_cf = term->cflags;
98 term->cflags = tios->c_cflag;
104 pot_ops = term->tp_cap->ops;
106 if (tios->c_baud != term->iospeed) {
107 term->iospeed = tios->c_baud;
109 pot_ops->set_speed(term->chdev, tios->c_baud);
112 if (old_cf != tios->c_cflag) {
113 pot_ops->set_cntrl_mode(term->chdev, tios->c_cflag);
127 tdev_do_write(struct device* dev, void* buf, off_t fpos, size_t len)
129 struct term* tdev = termdev(dev);
130 lbuf_ref_t current = ref_current(&tdev->line_out);
133 wrsz += rbuffer_puts(
134 deref(current), &((char*)buf)[wrsz], len - wrsz);
136 if (rbuffer_full(deref(current))) {
141 if (!rbuffer_empty(deref(current))) {
148 tdev_do_read(struct device* dev, void* buf, off_t fpos, size_t len)
150 struct term* tdev = termdev(dev);
151 lbuf_ref_t current = ref_current(&tdev->line_in);
155 while (cont && rdsz < len) {
156 cont = term_read(tdev);
157 rdsz += rbuffer_gets(
158 deref(current), &((char*)buf)[rdsz], len - rdsz);
161 tdev->line_in.sflags = 0;
165 static cc_t default_cc[_NCCS] = {4, '\n', 0x7f, 3, 1, 24, 22, 0, 0, 1, 1};
168 load_default_setting(struct term* tdev)
170 tdev->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO | _ECHOE | _ECHONL;
171 tdev->iflags = _ICRNL | _IGNBRK;
172 tdev->oflags = _ONLCR | _OPOST;
173 tdev->iospeed = _B9600;
174 memcpy(tdev->cc, default_cc, _NCCS * sizeof(cc_t));
178 alloc_term_buffer(struct term* terminal, size_t sz_hlf)
180 line_alloc(&terminal->line_in, sz_hlf);
181 line_alloc(&terminal->line_out, sz_hlf);
182 terminal->scratch_pad = valloc(sz_hlf);
185 struct termport_potens*
186 term_attach_potens(struct device* chardev,
187 struct termport_pot_ops* ops, char* suffix)
189 struct term* terminal;
191 struct termport_potens* tp_cap;
193 terminal = vzalloc(sizeof(struct term));
198 tdev = device_allocseq(NULL, terminal);
199 terminal->dev = tdev;
200 terminal->chdev = chardev;
202 tdev->ops.read = tdev_do_read;
203 tdev->ops.write = tdev_do_write;
204 tdev->ops.exec_cmd = term_exec_cmd;
206 waitq_init(&terminal->line_in_event);
208 alloc_term_buffer(terminal, 1024);
211 int cdev_var = DEV_VAR_FROM(chardev->ident.unique);
212 register_device(tdev, &termdev_class, "tty%s%d", suffix, cdev_var);
214 register_device_var(tdev, &termdev_class, "tty");
217 INFO("spawned: %s", tdev->name_val);
219 tp_cap = new_potens(potens(TERMPORT), struct termport_potens);
220 tp_cap->ops = ops ?: &default_termport_pot_ops;
222 terminal->tp_cap = tp_cap;
223 tp_cap->term = terminal;
225 device_grant_potens(tdev, potens_meta(tp_cap));
227 load_default_setting(terminal);
233 term_bind(struct term* term, struct device* chdev)
235 device_lock(term->dev);
239 device_unlock(term->dev);
245 line_alloc(struct linebuffer* lbf, size_t sz_hlf)
247 char* buffer = valloc(sz_hlf * 2);
248 memset(lbf, 0, sizeof(*lbf));
249 lbf->current = rbuffer_create(buffer, sz_hlf);
250 lbf->next = rbuffer_create(&buffer[sz_hlf], sz_hlf);
251 lbf->sz_hlf = sz_hlf;
255 line_free(struct linebuffer* lbf, size_t sz_hlf)
258 (void*)MIN((ptr_t)lbf->current->buffer, (ptr_t)lbf->next->buffer);
263 term_sendsig(struct term* tdev, int signal)
265 if ((tdev->lflags & _ISIG)) {
266 signal_send(-tdev->fggrp, signal);
267 pwake_all(&tdev->line_in_event);