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>
9 #include <usr/lunaix/ioctl_defs.h>
12 #define termdev(dev) ((struct term*)(dev)->underlay)
14 extern struct term_lcntl ansi_line_controller;
15 static struct term_lcntl* line_controls[] = {[ANSI_LCNTL] =
16 &ansi_line_controller};
17 #define LCNTL_TABLE_LEN (sizeof(line_controls) / sizeof(struct term_lcntl*))
19 static struct devclass termdev = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_VTERM);
22 term_exec_cmd(struct device* dev, u32_t req, va_list args)
24 struct term* term = termdev(dev);
31 pid_t pgid = va_arg(args, pid_t);
42 u32_t lcntl_idx = va_arg(args, u32_t);
43 struct term_lcntl* lcntl = term_get_lcntl(lcntl_idx);
50 term_push_lcntl(term, lcntl);
56 case TDEV_TCSETCHDEV: {
57 int fd = va_arg(args, int);
60 if (vfs_getfd(fd, &vfd)) {
65 struct device* cdev = device_cast(vfd->file->inode->data);
70 if (cdev->dev_type != DEV_IFSEQ) {
75 term_bind(term, cdev);
78 case TDEV_TCGETCHDEV: {
79 struct dev_info* devinfo = va_arg(args, struct dev_info*);
87 device_populate_info(term->chdev, devinfo);
91 case TDEV_TCGETATTR: {
92 struct _termios* tios = va_arg(args, struct _termios*);
93 *tios = (struct _termios){.c_oflag = term->oflags,
94 .c_iflag = term->iflags,
95 .c_lflag = term->lflags};
96 memcpy(tios->c_cc, term->cc, _NCCS * sizeof(cc_t));
97 tios->c_baud = term->iospeed;
99 case TDEV_TCSETATTR: {
100 struct _termios* tios = va_arg(args, struct _termios*);
101 term->iflags = tios->c_iflag;
102 term->oflags = tios->c_oflag;
103 term->lflags = tios->c_lflag;
104 memcpy(term->cc, tios->c_cc, _NCCS * sizeof(cc_t));
106 if (tios->c_baud != term->iospeed) {
107 term->iospeed = tios->c_baud;
108 if (!term->chdev_ops.set_speed) {
112 term->chdev_ops.set_speed(term->chdev, tios->c_baud);
126 tdev_do_write(struct device* dev, void* buf, size_t offset, size_t len)
128 struct term* tdev = termdev(dev);
129 lbuf_ref_t current = ref_current(&tdev->line_out);
132 wrsz += rbuffer_puts(deref(current), &((char*)buf)[offset + wrsz],
134 if (rbuffer_full(deref(current))) {
143 tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len)
145 struct term* tdev = termdev(dev);
146 lbuf_ref_t current = ref_current(&tdev->line_in);
149 while (cont && rdsz < len) {
150 if (rbuffer_empty(deref(current))) {
151 tdev->line_in.sflags = 0;
152 cont = term_read(tdev);
155 rdsz += rbuffer_gets(deref(current), &((char*)buf)[offset + rdsz],
162 static cc_t default_cc[_NCCS] = {4, '\n', 8, 3, 1, 24, 22, 0, 0, 1, 1};
165 term_create(struct device* chardev, char* suffix)
167 struct term* terminal = vzalloc(sizeof(struct term));
173 terminal->dev = device_allocseq(NULL, terminal);
174 terminal->chdev = chardev;
176 terminal->dev->ops.read = tdev_do_read;
177 terminal->dev->ops.write = tdev_do_write;
179 llist_init_head(&terminal->lcntl_stack);
180 line_alloc(&terminal->line_in, 1024);
181 line_alloc(&terminal->line_out, 1024);
184 int cdev_var = DEV_VAR_FROM(chardev->ident.unique);
185 device_register(terminal->dev, &termdev, "tty%s%d", suffix, cdev_var);
187 device_register(terminal->dev, &termdev, "tty%d", termdev.variant++);
190 terminal->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO;
191 terminal->iflags = _ICRNL;
192 memcpy(terminal->cc, default_cc, _NCCS * sizeof(cc_t));
198 term_bind(struct term* term, struct device* chdev)
200 device_lock(term->dev);
204 device_unlock(term->dev);
210 term_get_lcntl(u32_t lcntl_index)
212 if (lcntl_index >= LCNTL_TABLE_LEN) {
216 struct term_lcntl* lcntl_template = line_controls[lcntl_index];
217 struct term_lcntl* lcntl_instance = valloc(sizeof(struct term_lcntl));
219 if (!lcntl_instance) {
223 lcntl_instance->process_and_put = lcntl_template->process_and_put;
225 return lcntl_instance;
229 term_push_lcntl(struct term* term, struct term_lcntl* lcntl)
231 device_lock(term->dev);
233 llist_append(&term->lcntl_stack, &lcntl->lcntls);
235 device_unlock(term->dev);
241 term_pop_lcntl(struct term* term)
243 if (term->lcntl_stack.prev == &term->lcntl_stack) {
247 device_lock(term->dev);
249 struct term_lcntl* lcntl =
250 list_entry(term->lcntl_stack.prev, struct term_lcntl, lcntls);
251 llist_delete(term->lcntl_stack.prev);
255 device_unlock(term->dev);
261 line_alloc(struct linebuffer* lbf, size_t sz_hlf)
263 char* buffer = valloc(sz_hlf * 2);
264 memset(lbf, 0, sizeof(*lbf));
265 lbf->current = rbuffer_create(buffer, sz_hlf);
266 lbf->next = rbuffer_create(&buffer[sz_hlf], sz_hlf);
267 lbf->sz_hlf = sz_hlf;
271 line_free(struct linebuffer* lbf, size_t sz_hlf)
274 (void*)MIN((ptr_t)lbf->current->buffer, (ptr_t)lbf->next->buffer);
279 term_sendsig(struct term* tdev, int signal)
281 if ((tdev->lflags & _ISIG)) {
282 proc_setsignal(get_process(tdev->fggrp), signal);