729e5496b083bc22e51b2bac9ec1c31f407c0152
[lunaix-os.git] / lunaix-os / hal / term / term_io.c
1 #include <hal/term.h>
2
3 #include <lunaix/clock.h>
4 #include <lunaix/sched.h>
5
6 #include <usr/lunaix/term.h>
7
8 #define ONBREAK (LSTATE_EOF | LSTATE_SIGRAISE)
9 #define ONSTOP (LSTATE_SIGRAISE | LSTATE_EOL | LSTATE_EOF)
10
11 static int
12 do_read_raw(struct term* tdev)
13 {
14     struct device* chdev = tdev->chdev;
15
16     struct linebuffer* line_in = &tdev->line_in;
17     size_t max_lb_sz = line_in->sz_hlf;
18
19     line_flip(line_in);
20
21     char* inbuffer = line_in->current->buffer;
22     size_t min = tdev->cc[_VMIN] - 1;
23     size_t sz = chdev->ops.read_async(chdev, inbuffer, 0, max_lb_sz);
24     time_t t = clock_systime(), dt = 0;
25     time_t expr = (tdev->cc[_VTIME] * 100) - 1;
26
27     while (sz <= min && dt <= expr) {
28         // XXX should we held the device lock while we are waiting?
29         sched_yieldk();
30         dt = clock_systime() - t;
31         t += dt;
32
33         max_lb_sz -= sz;
34
35         // TODO pass a flags to read to indicate it is non blocking ops
36         sz += chdev->ops.read_async(chdev, inbuffer, sz, max_lb_sz);
37     }
38
39     rbuffer_puts(line_in->next, inbuffer, sz);
40     line_flip(line_in);
41
42     return 0;
43 }
44
45 static int
46 do_read_raw_canno(struct term* tdev)
47 {
48     struct device* chdev = tdev->chdev;
49     struct linebuffer* line_in = &tdev->line_in;
50     struct rbuffer* current_buf = line_in->current;
51     int sz = chdev->ops.read(chdev, current_buf->buffer, 0, line_in->sz_hlf);
52
53     current_buf->ptr = sz;
54     current_buf->len = sz;
55
56     return sz;
57 }
58
59 static int
60 term_read_noncano(struct term* tdev)
61 {
62     struct device* chdev = tdev->chdev;
63     return do_read_raw(tdev);
64     ;
65 }
66
67 static int
68 term_read_cano(struct term* tdev)
69 {
70     struct device* chdev = tdev->chdev;
71     struct linebuffer* line_in = &tdev->line_in;
72     int size = 0;
73
74     while (!(line_in->sflags & ONSTOP)) {
75         // move all hold-out content to 'next' buffer
76         line_flip(line_in);
77
78         size += do_read_raw_canno(tdev);
79         lcntl_transform_inseq(tdev);
80     }
81
82     return 0;
83 }
84
85 int
86 term_read(struct term* tdev)
87 {
88     if ((tdev->lflags & _ICANON)) {
89         return term_read_cano(tdev);
90     }
91     return term_read_noncano(tdev);
92 }
93
94 int
95 term_flush(struct term* tdev)
96 {
97     if ((tdev->oflags & _OPOST)) {
98         lcntl_transform_inseq(tdev);
99     }
100
101     struct linebuffer* line_out = &tdev->line_out;
102     size_t xmit_len = line_out->current->len;
103     void* xmit_buf = line_out->next->buffer;
104
105     rbuffer_gets(line_out->current, xmit_buf, xmit_len);
106
107     off_t off = 0;
108     int ret = 0;
109     while (xmit_len && ret >= 0) {
110         ret = tdev->chdev->ops.write(tdev->chdev, xmit_buf, off, xmit_len);
111         xmit_len -= ret;
112         off += ret;
113     }
114
115     // put back the left over if transmittion went south
116     rbuffer_puts(line_out->current, xmit_buf, xmit_len);
117
118     return off;
119 }