X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/78cd005fac540973751b5a108c37a715bc64b5a2..59ecf21e36b2332f6adf2a568ef555283d8c119a:/lunaix-os/hal/term/term_io.c?ds=sidebyside diff --git a/lunaix-os/hal/term/term_io.c b/lunaix-os/hal/term/term_io.c new file mode 100644 index 0000000..94e61d6 --- /dev/null +++ b/lunaix-os/hal/term/term_io.c @@ -0,0 +1,118 @@ +#include + +#include +#include + +#include + +#define ONBREAK (LSTATE_EOF | LSTATE_SIGRAISE) +#define ONSTOP (LSTATE_SIGRAISE | LSTATE_EOL | LSTATE_EOF) + +static int +do_read_raw(struct term* tdev) +{ + struct device* chdev = tdev->chdev; + + struct linebuffer* line_in = &tdev->line_in; + size_t max_lb_sz = line_in->sz_hlf; + + line_flip(line_in); + + char* inbuffer = line_in->current->buffer; + size_t min = tdev->cc[_VMIN] - 1; + size_t sz = chdev->ops.read(chdev, inbuffer, 0, max_lb_sz); + time_t t = clock_systime(), dt = 0; + time_t expr = (tdev->cc[_VTIME] * 100) - 1; + + while (sz <= min && dt <= expr) { + // XXX should we held the device lock while we are waiting? + sched_yieldk(); + dt = clock_systime() - t; + t += dt; + + max_lb_sz -= sz; + + // TODO pass a flags to read to indicate it is non blocking ops + sz += + chdev->ops.read(chdev, inbuffer, sz, max_lb_sz); + } + + rbuffer_puts(line_in->next, inbuffer, sz); + line_flip(line_in); + + return 0; +} + +static int +do_read_raw_canno(struct term* tdev) { + struct device* chdev = tdev->chdev; + struct linebuffer* line_in = &tdev->line_in; + struct rbuffer* current_buf = line_in->current; + int sz = chdev->ops.read(chdev, current_buf->buffer, 0, line_in->sz_hlf); + + current_buf->ptr = sz; + current_buf->len = sz; + + return sz; +} + +static int +term_read_noncano(struct term* tdev) +{ + struct device* chdev = tdev->chdev; + return do_read_raw(tdev);; +} + +static int +term_read_cano(struct term* tdev) +{ + struct device* chdev = tdev->chdev; + struct linebuffer* line_in = &tdev->line_in; + int size = 0; + + while (!(line_in->sflags & ONSTOP)) { + // move all hold-out content to 'next' buffer + line_flip(line_in); + + size += do_read_raw_canno(tdev); + lcntl_transform_inseq(tdev); + } + + return 0; +} + +int +term_read(struct term* tdev) +{ + if ((tdev->lflags & _ICANON)) { + return term_read_cano(tdev); + } + return term_read_noncano(tdev); +} + +int +term_flush(struct term* tdev) +{ + if ((tdev->oflags & _OPOST)) { + lcntl_transform_inseq(tdev); + } + + struct linebuffer* line_out = &tdev->line_out; + size_t xmit_len = line_out->current->len; + void* xmit_buf = line_out->next->buffer; + + rbuffer_gets(line_out->current, xmit_buf, xmit_len); + + off_t off = 0; + int ret = 0; + while (xmit_len && ret >= 0) { + ret = tdev->chdev->ops.write(tdev->chdev, xmit_buf, off, xmit_len); + xmit_len -= ret; + off += ret; + } + + // put back the left over if transmittion went south + rbuffer_puts(line_out->current, xmit_buf, xmit_len); + + return off; +} \ No newline at end of file