2 #include <klibc/string.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/spike.h>
6 #include <lunaix/status.h>
8 #include <usr/lunaix/ioctl_defs.h>
12 extern struct term_lcntl ansi_line_controller;
13 static struct term_lcntl* line_controls[] = { [ANSI_LCNTL] =
14 &ansi_line_controller };
15 #define LCNTL_TABLE_LEN (sizeof(line_controls) / sizeof(struct term_lcntl*))
18 term_exec_cmd(struct device* dev, u32_t req, va_list args)
20 struct term* term = (struct term*)dev->underlay;
27 pid_t pgid = va_arg(args, pid_t);
38 u32_t lcntl_idx = va_arg(args, u32_t);
39 struct term_lcntl* lcntl = term_get_lcntl(lcntl_idx);
46 term_push_lcntl(term, lcntl);
53 int fd = va_arg(args, int);
56 if (vfs_getfd(fd, &vfd)) {
61 struct device* cdev = device_cast(vfd->file->inode->data);
66 if (cdev->dev_type != DEV_IFSEQ) {
71 term_bind(term, cdev);
75 struct dev_info* devinfo = va_arg(args, struct dev_info*);
83 device_populate_info(term->chdev, devinfo);
98 term_write(struct device* dev, void* buf, size_t offset, size_t len)
100 struct term* term = (struct term*)dev->underlay;
101 size_t sz = MIN(len, term->line.sz_hlf);
107 device_lock(term->dev);
109 memcpy(term->line.current, &((char*)buf)[offset], sz);
111 struct term_lcntl *lcntl, *n;
112 llist_for_each(lcntl, n, &term->lcntl_stack, lcntls)
114 sz = lcntl->apply(term, term->line.current, sz);
115 line_flip(&term->line);
118 int errcode = term_sendline(term, sz);
120 device_unlock(term->dev);
126 term_read(struct device* dev, void* buf, size_t offset, size_t len)
128 struct term* term = (struct term*)dev->underlay;
129 size_t sz = MIN(len, term->line.sz_hlf);
135 device_lock(term->dev);
137 sz = term_readline(term, sz);
139 device_unlock(term->dev);
143 struct term_lcntl *pos, *n;
144 llist_for_each(pos, n, &term->lcntl_stack, lcntls)
146 sz = pos->apply(term, term->line.current, sz);
147 line_flip(&term->line);
150 memcpy(&((char*)buf)[offset], term->line.current, sz);
152 device_unlock(term->dev);
160 struct term* terminal = valloc(sizeof(struct term));
166 terminal->dev = device_allocseq(NULL, terminal);
168 terminal->dev->ops.read = term_read;
169 terminal->dev->ops.write = term_write;
171 llist_init_head(&terminal->lcntl_stack);
172 line_alloc(&terminal->line, 1024);
178 term_bind(struct term* term, struct device* chdev)
180 device_lock(term->dev);
184 device_unlock(term->dev);
190 term_get_lcntl(u32_t lcntl_index)
192 if (lcntl_index >= LCNTL_TABLE_LEN) {
196 struct term_lcntl* lcntl_template = line_controls[lcntl_index];
197 struct term_lcntl* lcntl_instance = valloc(sizeof(struct term_lcntl));
199 if (!lcntl_instance) {
203 lcntl_instance->apply = lcntl_template->apply;
205 return lcntl_instance;
209 term_push_lcntl(struct term* term, struct term_lcntl* lcntl)
211 device_lock(term->dev);
213 llist_append(&term->lcntl_stack, &lcntl->lcntls);
215 device_unlock(term->dev);
221 term_pop_lcntl(struct term* term)
223 if (term->lcntl_stack.prev == &term->lcntl_stack) {
227 device_lock(term->dev);
229 struct term_lcntl* lcntl =
230 list_entry(term->lcntl_stack.prev, struct term_lcntl, lcntls);
231 llist_delete(term->lcntl_stack.prev);
235 device_unlock(term->dev);
241 line_flip(struct linebuffer* lbf)
243 char* tmp = lbf->current;
244 lbf->current = lbf->next;
249 line_alloc(struct linebuffer* lbf, size_t sz_hlf)
251 char* buffer = valloc(sz_hlf * 2);
252 lbf->current = buffer;
253 lbf->next = &buffer[sz_hlf];
254 lbf->sz_hlf = sz_hlf;
258 line_free(struct linebuffer* lbf, size_t sz_hlf)
260 void* ptr = (void*)MIN((ptr_t)lbf->current, (ptr_t)lbf->next);
265 term_sendline(struct term* tdev, size_t len)
267 struct device* chdev = tdev->chdev;
271 int code = chdev->ops.write(chdev, tdev->line.current, 0, len);
273 device_unlock(chdev);
279 term_readline(struct term* tdev, size_t len)
281 struct device* chdev = tdev->chdev;
285 int code = chdev->ops.read(chdev, tdev->line.current, 0, len);
287 device_unlock(chdev);
293 term_init(struct device_def* devdef)
295 struct term* terminal = term_create();
296 struct device* tdev = device_allocseq(NULL, terminal);
297 tdev->ops.read = term_read;
298 tdev->ops.write = term_write;
299 tdev->ops.exec_cmd = term_exec_cmd;
301 devdef->class.variant++;
302 device_register(tdev, &devdef->class, "tty%d", devdef->class.variant);
307 static struct device_def vterm_def = {
308 .class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_VTERM),
309 .name = "virtual terminal",
312 EXPORT_DEVICE(vterm, &vterm_def, load_on_demand);