* Make the ksym table built-in with kernel image, thus remove the need
[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_pass();
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], 0, 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 static int
67 term_read_cano(struct term* tdev)
68 {
69     struct device* chdev = tdev->chdev;
70     struct linebuffer* line_in = &tdev->line_in;
71     int size = 0;
72
73     while (!(line_in->sflags & ONSTOP)) {
74         // move all hold-out content to 'next' buffer
75         line_flip(line_in);
76
77         size += do_read_raw_canno(tdev);
78         lcntl_transform_inseq(tdev);
79     }
80
81     return 0;
82 }
83
84 int
85 term_read(struct term* tdev)
86 {
87     if ((tdev->lflags & _ICANON)) {
88         return term_read_cano(tdev);
89     }
90     return term_read_noncano(tdev);
91 }
92
93 int
94 term_flush(struct term* tdev)
95 {
96     struct linebuffer* line_out = &tdev->line_out;
97     char* xmit_buf = tdev->scratch_pad;
98     lbuf_ref_t current_ref = ref_current(line_out);
99
100     int count = 0;
101
102     while (!rbuffer_empty(deref(current_ref))) {
103         if ((tdev->oflags & _OPOST)) {
104             lcntl_transform_outseq(tdev);
105         }
106
107         size_t xmit_len = line_out->current->len;
108
109         rbuffer_gets(line_out->current, xmit_buf, xmit_len);
110
111         off_t off = 0;
112         int ret = 0;
113         while (xmit_len && ret >= 0) {
114             ret = tdev->chdev->ops.write(tdev->chdev, &xmit_buf[off], 0, xmit_len);
115             xmit_len -= ret;
116             off += ret;
117             count += ret;
118         }
119
120         // put back the left over if transmittion went south
121         rbuffer_puts(line_out->current, xmit_buf, xmit_len);
122
123         line_flip(line_out);
124     }
125
126     return count;
127 }