rewrite the device subsystem interfaces (#48)
[lunaix-os.git] / lunaix-os / hal / term / term_io.c
1 #include <hal/term.h>
2
3 #include <lunaix/clock.h>
4 #include <lunaix/kpreempt.h>
5
6 #include <usr/lunaix/term.h>
7
8 #define ONBREAK (LEVT_EOF | LEVT_SIGRAISE)
9 #define ONSTOP (LEVT_SIGRAISE | LEVT_EOL | LEVT_EOF)
10
11 static int
12 do_read_raw(struct term* tdev)
13 {
14     struct linebuffer* line_in;
15     lbuf_ref_t current_buf;
16     size_t min, sz = 0;
17     time_t t, expr, dt = 0;
18     
19     line_in = &tdev->line_in;
20     current_buf = ref_current(line_in);
21
22     min = tdev->cc[_VMIN] - 1;
23     t = clock_systime();
24     expr = (tdev->cc[_VTIME] * 100) - 1;
25
26     min = MIN(min, (size_t)line_in->sz_hlf);
27     while (sz <= min && dt <= expr) {
28         // XXX should we held the device lock while we are waiting?
29         yield_current();
30         dt = clock_systime() - t;
31         t += dt;
32
33         sz = deref(current_buf)->len;
34     }
35
36     return 0;
37 }
38
39 static inline int
40 term_read_cano(struct term* tdev)
41 {
42     struct linebuffer* line_in;
43
44     line_in = &tdev->line_in;
45     while (!(line_in->sflags & ONSTOP)) {
46         pwait(&tdev->line_in_event);
47     }
48
49     return 0;
50 }
51
52 int
53 term_read(struct term* tdev)
54 {
55     if ((tdev->lflags & _ICANON)) {
56         return term_read_cano(tdev);
57     }
58
59     return do_read_raw(tdev);
60 }
61
62 int
63 term_flush(struct term* tdev)
64 {
65     struct device* chardev;
66     struct linebuffer* line_out = &tdev->line_out;
67     char* xmit_buf = tdev->scratch_pad;
68     lbuf_ref_t current_ref = ref_current(line_out);
69     
70     int count = 0;
71
72     chardev = tdev->chdev;
73
74     while (!rbuffer_empty(deref(current_ref))) {
75         if ((tdev->oflags & _OPOST)) {
76             lcntl_transform_outseq(tdev);
77         }
78
79         size_t xmit_len = line_out->current->len;
80
81         rbuffer_gets(line_out->current, xmit_buf, xmit_len);
82
83         off_t off = 0;
84         int ret = 0;
85         while (xmit_len && ret >= 0) {
86             ret = chardev->ops.write(chardev, &xmit_buf[off], 0, xmit_len);
87             xmit_len -= ret;
88             off += ret;
89             count += ret;
90         }
91
92         // put back the left over if transmittion went south
93         rbuffer_puts(line_out->current, xmit_buf, xmit_len);
94
95         line_flip(line_out);
96     }
97
98     return count;
99 }
100
101 void
102 term_notify_data_avaliable(struct termport_potens* cap)
103 {
104     struct term* term;
105     struct device* term_chrdev;
106     struct linebuffer* line_in;
107     lbuf_ref_t current_ref;
108     char* buf;
109     int sz;
110
111     term = cap->term;
112     term_chrdev = term->chdev;
113     line_in = &term->line_in;
114     current_ref = ref_current(line_in);
115     
116     // make room for current buf
117     line_flip(line_in);
118     buf = deref(current_ref)->buffer;
119
120     sz = term_chrdev->ops.read_async(term_chrdev, buf, 0, line_in->sz_hlf);
121     rbuffer_setcontent(deref(current_ref), sz);
122
123     if ((term->lflags & _ICANON)) {
124         lcntl_transform_inseq(term);
125         // write all processed to next, and flip back to current
126     }
127
128     pwake_all(&term->line_in_event);
129 }